排序八卦炉之冒泡、快排【完整版】

文章目录

  • 1.冒泡排序
    • 1.1代码实现
    • 1.2复杂度
  • 2.快速排序
    • 2.1人物及思想介绍【源于百度】
    • 2.2hoare【霍尔】版本
      • 1.初识代码
      • 2.代码分析
      • 3.思其因果
    • 2.3挖坑版本
      • 1.初始代码
      • 2.代码分析
      • 3.思想比较
    • 2.4指针版本
      • 1.初识代码
      • 2.代码分析
      • 3.问题探讨
    • 2.5集体优化
    • 2.6极致优化
    • 2.7非递归版本
      • 1.初识代码
      • 2.代码分析
    • 2.8相关博客及完整代码

在这里插入图片描述

1.冒泡排序

在这里插入图片描述

1.1代码实现

//插入排序  O(N)~O(N^2)
//冒泡排序  O(N)~O(N^2)
//当数据有序 二者均为O(N)
//当数据接近有序或局部有序 插排更优
void BubbleSort(int* a, int n)
{assert(a);int flag = 1;for (int i = 0; flag && i < n - 1; ++i){flag = 0;for (int j = 0; j < n - 1 - i; ++j){if (a[j] > a[j + 1]){Swap(&a[j - 1], &a[j]);flag = 1;}}}
}

1.2复杂度

  1. 最坏:
    比较n-1轮
    每一轮比较次数:n n-1 n-2 n-3 … 1 ≈ N^2
  2. 最优:
    比较n-1轮
    数据有序–每一轮只判断不比较 – N

2.快速排序

2.1人物及思想介绍【源于百度】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.2hoare【霍尔】版本

1.初识代码

//霍尔版本
int PartSort1(int* a, int begin, int end)
{int left = begin, right = end, x = left;while (left < right){//右找小while (left < right && a[right] >= a[x])--right;//左找大while (left < right && a[left] <= a[x])++left;Swap(&a[left], &a[right]);}Swap(&a[x], &a[left]);x = left;return x;
}
void QuickSort(int* a, int begin, int end)    
{//begin:左区间左边界下标 //end  :右区间右边界下标//begin==end:数据量=1 无需排序 直接返回//begin>end :无效区间 无需排序 直接返回if (begin >= end)return;int x = PartSort1(a, begin, end);// [begin, x - 1] x [x + 1, end]QuickSort(a, begin, x - 1);QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思其因果

Q:为什么a[x]【作为基准值key】置于左侧 – 右边先移动?
A:目的是为了保证相遇位置的值<=key 从而把key与相遇值交换 不打乱“左放小,右放大”的思想
在这里插入图片描述

2.3挖坑版本

1.初始代码

//挖坑版本
int PartSort2(int* a, int begin, int end)
{int x = begin, key = a[begin];while (begin < end){while (begin < end && a[end] >= key)--end;a[x] = a[end];x = end;while (begin < end && a[begin] <= key)++begin;a[x] = a[begin];x = begin;}a[x] = key;return x;
}
void QuickSort(int* a, int begin, int end)    
{//begin:左区间左边界下标 //end  :右区间右边界下标//begin==end:数据量=1 无需排序 直接返回//begin>end :无效区间 无需排序 直接返回if (begin >= end)return;int x = PartSort1(a, begin, end);// [begin, x - 1] x [x + 1, end]QuickSort(a, begin, x - 1);QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.思想比较

霍尔版本:右找小 左找打 大小交换 依次递归
挖坑版本:记录key值 x位–置空 右找小入坑 坑位更新 左找大入坑 坑位更新 依次递归

在这里插入图片描述

2.4指针版本

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointerint prv = begin, cp = begin + 1, x = begin;while (cp <= end){if (a[cp] < a[x] && ++prv != cp)Swap(&a[prv], &a[cp]);++cp;}Swap(&a[prv], &a[x]);x = prv;return x;
}
void QuickSort(int* a, int begin, int end)    
{//begin:左区间左边界下标 //end  :右区间右边界下标//begin==end:数据量=1 无需排序 直接返回//begin>end :无效区间 无需排序 直接返回if (begin >= end)return;int x = PartSort3(a, begin, end);// [begin, x - 1] x [x + 1, end]QuickSort(a, begin, x - 1);QuickSort(a, x+1, end);
}

2.代码分析

在这里插入图片描述

3.问题探讨

在这里插入图片描述

2.5集体优化

//快速排序   O(N * logN)
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[begin] < a[mid]){if (a[mid] < a[end])return mid;else if (a[begin] < a[end])return end;elsereturn begin;}else //a[begin] >= a[mid]{if (a[mid] > a[end])return mid;else if (a[begin] < a[end])return begin;elsereturn end;}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{int left = begin, right = end, x = left;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]);while (left < right){//右找小while (left < right && a[right] >= a[x])--right;//左找大while (left < right && a[left] <= a[x])++left;Swap(&a[left], &a[right]);}Swap(&a[x], &a[left]);x = left;return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{int x = begin;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]); int key = a[x];while (begin < end){while (begin < end && a[end] >= key)--end;a[x] = a[end];x = end;while (begin < end && a[begin] <= key)++begin;a[x] = a[begin];x = begin;}a[x] = key;return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]);while (cp <= end){if (a[cp] < a[x] && ++prv != cp)Swap(&a[prv], &a[cp]);++cp;}Swap(&a[prv], &a[x]);x = prv;return x;
}
void QuickSort(int* a, int begin, int end)    
{//begin:左区间左边界下标 //end  :右区间右边界下标//begin==end:数据量=1 无需排序 直接返回//begin>end :无效区间 无需排序 直接返回if (begin >= end)return;int x = PartSort2(a, begin, end);// [begin, x - 1] x [x + 1, end]QuickSort(a, begin, x - 1);QuickSort(a, x+1, end);
}

2.6极致优化

在这里插入图片描述

在这里插入图片描述

2.7非递归版本

递归版本存在的问题:若递归层次太深 导致栈溢出问题
递归改非递归的方法:

  1. 直接改循环 – 斐波那契数列、归并排序等
  2. 数据结构的栈(Stack)模拟递归【Stack的空间是从堆申请的 堆内存比栈内存大】

1.初识代码

int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]);while (cp <= end){if (a[cp] < a[x] && ++prv != cp)Swap(&a[prv], &a[cp]);++cp;}Swap(&a[prv], &a[x]);x = prv;return x;
}
void QuickSort_NonRecursion(int* a, int begin, int end)
{ST st;StackInit(&st);StackPush(&st, begin);StackPush(&st, end);while (!StackEmpty(&st)){int right = StackTop(&st);StackPop(&st);int left = StackTop(&st);StackPop(&st);int x = PartSort3(a, left, right);if (x + 1 < right){StackPush(&st, x + 1);StackPush(&st, right);}// [left, x-1] x [x+1, right]if (left < x - 1){StackPush(&st, left);StackPush(&st, x - 1);}}StackDestroy(&st);
}

2.代码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.8相关博客及完整代码

点击 [qsort与bubble之间不为人知的关系](htt p://t.csdn.cn/filuW) 查看博主之前关于分析这两个排序的博客。

//快速排序   O(N * logN)
int count = 0;  //测试递归次数
//对任意区间三值取中位数
int GetMid_X(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[begin] < a[mid]){if (a[mid] < a[end])return mid;else if (a[begin] < a[end])return end;elsereturn begin;}else //a[begin] >= a[mid]{if (a[mid] > a[end])return mid;else if (a[begin] < a[end])return begin;elsereturn end;}
}
//霍尔版本
int PartSort1(int* a, int begin, int end)
{int left = begin, right = end, x = left;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]);while (left < right){//右找小while (left < right && a[right] >= a[x])--right;//左找大while (left < right && a[left] <= a[x])++left;Swap(&a[left], &a[right]);}Swap(&a[x], &a[left]);x = left;return x;
}
//挖坑版本
int PartSort2(int* a, int begin, int end)
{int x = begin;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]); int key = a[x];while (begin < end){while (begin < end && a[end] >= key)--end;a[x] = a[end];x = end;while (begin < end && a[begin] <= key)++begin;a[x] = a[begin];x = begin;}a[x] = key;return x;
}  
//指针版本
int PartSort3(int* a, int begin, int end)
{   //prv:previous  cp:current pointerint prv = begin, cp = begin + 1, x = begin;//确定更合适的keyint mid_x = GetMid_X(a, begin, end);Swap(&a[x], &a[mid_x]);while (cp <= end){if (a[cp] < a[x] && ++prv != cp)Swap(&a[prv], &a[cp]);++cp;}Swap(&a[prv], &a[x]);x = prv;return x;
}void QuickSort(int* a, int begin, int end)
{count++;//begin:左区间左边界下标 //end  :右区间右边界下标//begin==end:数据量=1 无需排序 直接返回//begin>end :无效区间 无需排序 直接返回if (begin >= end)return;int x = PartSort3(a, begin, end);// [begin, x - 1] x [x + 1, end]QuickSort(a, begin, x - 1);QuickSort(a, x+1, end);
}/*
void QuickSort(int* a, int begin, int end)
{count++;if (begin >= end)return;if (end - begin > 10){int x = PartSort3(a, begin, end);// [begin, x-1] x [x+1, end]QuickSort(a, begin, x - 1);QuickSort(a, x + 1, end);}else InsertSort(a + begin, end - begin + 1);
}
*/
//非递归版本
void QuickSort_NonRecursion(int* a, int begin, int end)
{ST st;StackInit(&st);StackPush(&st, begin);StackPush(&st, end);while (!StackEmpty(&st)){int end = StackTop(&st);StackPop(&st);int begin = StackTop(&st);StackPop(&st);int x = PartSort3(a, begin, end);if (x + 1 < end){StackPush(&st, x + 1);StackPush(&st, end);}// [begin, x-1] x [x+1, end]if (begin < x - 1){StackPush(&st, begin);StackPush(&st, x - 1);}}StackDestroy(&st);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/22087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sql语句字符函数,数学函数

一、trim&#xff08;&#xff09;去掉前后单元格 SELECT LENGTH(TRIM( 张三 )) AS 姓名 trim&#xff08;aa from bb) 除掉bb中前后包含的aa&#xff0c;中间的保留 SELECT TRIM(班 FROM class) AS 姓名 FROM user_test 二、lpad&#xff08;&#xff09;用指定字符做左…

用Rust实现23种设计模式之桥接模式

桥接模式的优点&#xff1a; 桥接模式的设计目标是将抽象部分和实现部分分离&#xff0c;使它们可以独立变化。这种分离有以下几个优点&#xff1a; 解耦和灵活性&#xff1a;桥接模式可以将抽象部分和实现部分解耦&#xff0c;使它们可以独立地变化。这样&#xff0c;对于抽象…

【css】css实现一个简单的按钮

四种链接状态分别是&#xff1a; a:link - 正常的&#xff0c;未访问的链接a:visited - 用户访问过的链接a:hover - 用户将鼠标悬停在链接上时a:active - 链接被点击时 <style> a:link, a:visited {//未访问、访问过background-color: #07c160;//设置背景颜色color: wh…

Day10-NodeJS和NPM配置

Day10-NodeJS和NPM 一 Nodejs 1 简介 Nodejs学习中文网:https://www.nodeapp.cn/synopsis.html Nodejs的官网:https://nodejs.org/ 概念:Nodejs是JavaScript的服务端运行环境.Nodejs不是框架,也不是编程语言,就是一个运行环境. Nodejs是基于chrome V8引擎开发的一套js代码…

Java设计模式——类之间的关系

1.继承关系(泛化) 类与子类的关系&#xff0c;指一个类继承另外的一个类。 2.实现关系 一个类可以实现多个接口&#xff0c;实现所有接口的功能。 3.依赖关系 类B作为类A方法中的局部变量或者参数出现&#xff0c;表示A依赖B。 4.关联关系 类B作为类A中的成员变量出现&#…

Toyota Programming Contest 2023#4(AtCoder Beginner Contest 311)D题题解

文章目录 [Grid Ice Floor](https://atcoder.jp/contests/abc311/tasks/abc311_d)问题建模问题分析1.分析移动时前后两个点之间的联系2.方法1通过BFS将所有按照给定运动方式可以到达的点都标记代码 3.方法2采用DFS来标记路径上的点的运动状态代码 Grid Ice Floor 问题建模 给定…

linux快速安装Rabbitmq

linux快速安装Rabbitmq 准备yum仓库 # root执行rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.ascrpm --import https://packagecloud.io/rabbitmq/erlang/gpgkeyrpm --import https://packagecloud.io/ra…

测试岗?从功能测试进阶自动化测试开发,测试之路不迷茫...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 测试新人在想什么…

IO进程线程day7(2023.8.4)

一、Xmind整理&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;创建两个线程&#xff1a;其中一个线程拷贝前半部分&#xff0c;另一个线程拷贝后半部分。 只允许开一份资源&#xff0c;且用互斥锁方式实现。 提示&#xff1a;找临界区--->找临界资源。 #includ…

swagger相关问题

swagger相关问题 swagger版本为&#xff1a; <dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version> </dependency> <dependency><groupId&…

网络安全设备-等保一体机

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 等保一体机的功能 等保一体机产品主要依赖于其丰富的安全网元&#xff08;安全网元包括&#xff1a;防火…

sentinel组件

目录 定义 4.加SentinelResource,blockHander是超过阈值之后执行的函数 5.设置阈值 6.springboot集成sentinel 定义 1.sentinel知道当前流量大小&#xff0c;在浏览器和后端之间加sentinel控制流量&#xff0c;避免大批量的瞬时请求都达到服务上&#xff0c;将服务压垮 2.…

汉字姓名转拼音

import osimport pandas as pdfrom xpinyin import Pinyindownpath/Users/Kangyongqing/Downloads/ file1教师姓名转拼音.xlsxdtpd.read_excel(downpathfile1) print(dt.info()) dt[pinyin]dt[教师姓名].apply(lambda x:Pinyin().get_pinyin(x).split(-)[0].capitalize() .join…

谈谈 Kafka 的幂等性 Producer

使用消息队列&#xff0c;我们肯定希望不丢消息&#xff0c;也就是消息队列组件&#xff0c;需要保证消息的可靠交付。消息交付的可靠性保障&#xff0c;有以下三种承诺&#xff1a; 最多一次&#xff08;at most once&#xff09;&#xff1a;消息可能会丢失&#xff0c;但绝…

399. 除法求值

给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件&#xff0c;其中 equations[i] [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。 另有一些以数组 queries 表示的问题&#xff0c;其中 queries[j]…

linux的搭建以及网关配置

Linux 目前国内 Linux 更多的是应用于服务器上,而桌面操作系统更多使用的是 Windows 安装linux虚拟机 网址 VMware下载网址 点击Workstation 16 Pro for Windows下载 安装CentOS centO下载网址 依次点击 7.6.1810/ isos/ x86_64/ CentOS-7-x86_64-DVD-1810.…

编写一个最简单的Windows服务端和客户端程序

2023年8月4日&#xff0c;周五上午 编译器 我使用vs2022作为编译器 纯享版 服务端负责发送Hello给客户端&#xff0c; 客户端负责把Hello接收并打印出来。 服务端代码 #include<winsock2.h> #include<string.h> #pragma comment(lib, "ws2_32.lib")i…

Vue3 watch监听器

概览&#xff1a;watch监听器的定义以及使用场景。在vue3中的监听器的使用方式&#xff0c;watch的三个参数&#xff0c;以及进一步了解第一个参数可以是一个属性&#xff0c;也可以是一个数组的形式包含多个属性。 watch在vue3和vue2中的使用&#xff1a; vue3中&#xff1a…

使用Jackson自定义序列化操作(Jackson – Custom Serializer)

目录 Standard Serialization of an Object GraphCustom Serializer on the ObjectMapperCustom Serializer on the Class Standard Serialization of an Object Graph Data NoArgsConstructor AllArgsConstructor public class Item {public int id;public String itemName;p…

java中pageHelper插件各个函数介绍

PageHelper是一个用于对MyBatis进行分页查询的Java插件。它提供了一组函数来配置和使用分页功能。以下是PageHelper插件中几个常用函数的介绍&#xff1a; startPage(int pageNum, int pageSize) 该函数用于开启分页查询&#xff0c;指定要查询的页码&#xff08;pageNum&#…