八大排序(二)快速排序

一、快速排序的思想

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

二、快速排序的三种实现方法

2.1、Hoare

思想:取最左边key为基准值,用right指针找比key值小的元素,用left指针找比key位置大的元素,

将两位置值进行交换,最后,将key值放在二者相遇位置上,就可保证key左边都是比key小的值,

右边都是比key大的值,然后进行递归即可实现,从相遇点分割成两部分,在分别对左右两部分重

复上述排序。

代码实现 :           

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}
//Hoare
int partSort1(int* a, int left, int right)
{int key = left;while (right > left){//从右往左找小while (right > left && a[right] >= a[key]){right--;}//从左往右找大while (right > left && a[left] <= a[key]){left++;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[key]);return left;
}void QuickSort(int* arr, int begin,int end)
{if (begin >= end){return;}int keyi = partSort1(arr, begin, end);QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}

2.2、挖坑法                                                                                             

思想:取最左边或最右边值做key,右边形成一个坑,定义两个指针left、right指向头和尾。右边找

小值放到左边坑中右边形成新坑,左边找大值放到右边左边形成新坑,将key放到相遇位置。这时

key左边值均小于key,右边值均大于key。       

代码实现:  

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}//挖坑法
int partSort2(int* a, int left, int right)
{int hole = left;int key = a[left];while (right > left){//从右往左找小while (right > left && a[right] >= key){right--;}a[hole] = a[right];hole = right;//从左往右找大while (right > left && a[left] <= key){left++;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}void QuickSort(int* arr, int begin,int end)
{if (begin >= end){return;}int keyi = partSort2(arr, begin, end);QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}

   2.3、双指针法 

思想:     

1.选择数组中的第一个元素arr[startIndex]作为轴(pivot)

2.左指针为left,从最左边开始寻找第一个比pivot大的数

3.右指针为right,从最右面的一个元素开始向左寻找第一个小于等于pivot的数值

4.经过2,3两个步骤后,将会出现以下两种情况

​ (1):left和right没有相遇,此时进行交换,swap(arr,left,right);

​ (2):left和right相遇,做swap(arr,startIndex,left),然后返回left

5.partition中返回pivot用于分割数组,下一次用于排序的数组被分割为(startIndex,pivot-1),(pivot+1,endIndex)两段,进行递归操作

代码实现:

void Swap(int* p1, int* p2)
{int temp = *p1;*p1 = *p2;*p2 = temp;
}int partSort3(int* a, int left, int right)
{int prev = left;int cur = prev + 1;int key = left;while (cur <= right){if (a[cur] < a[key] && ++prev != cur){Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[prev], &a[key]);return prev;
}void QuickSort(int* arr, int begin,int end)
{if (begin >= end){return;int keyi = partSort3(arr, begin, end);QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);
}

三、快速排序的优化

3.1、三数取中

当要排序的数组有序或者相对有序,比如我们要把一个逆序的数组按顺序排列,这时我们如果还选

择left为key的话,效率就会非常的低。我们要排除这种低效的可能就要让Key的值相对靠中间一

点,对此我们可以在实现一个函数,选择处left ,right ,和mid三个数中数值中间的那个数。用这个

数作为key就会避免我们遇到的这类问题。


                        

代码实现:

//三数取中
int Getmid(int* a, int left, int right)
{int mid = (left + right) / 2;// left mid rightif (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] > a[right])  // mid是最大值{return left;}else{return right;}}else // a[left] > a[mid]{if (a[mid] > a[right]){return mid;}else if (a[left] < a[right]) // mid是最小{return left;}else{return right;}}
}

对此我们就可以改进上面的三种方法,都可以在三种方法的开头添加这段代码,使之让key为靠中间的数,避免数组为有序的排序时间效率低的问题。

	int midi = Getmid(a, left, right);Swap(&a[left], &a[midi]);

3.2、小区间优化 

我们递归的深度越高效率越高,但是我们刚开始递归时深度很低,所以效率低下,所以我们可以采用高深度的时候用快速排序,在低深度的时候用直接插入排序,会对运行效率有所提高。

void QuickSort(int* a, int begain, int end)
{if (begain >= end)return;//小区间优化法 当数据量比较大的时候可以通过调整参数(20),来减小递归次数,提高性能if ((end - begain) > 20){int meeti = HoareSort(a, begain, end);QuickSort(a, begain, meeti - 1);QuickSort(a, meeti + 1, end);}else{//数量比较少的时候用直接插入来排序InsertSort(a + begain, end - begain + 1);}}

四、非递归实现快速排序

递归需要在栈上为函数开辟空间,32位下,栈可使用的内存大小不超过2G,如果递归较深,依然可能会发生栈溢出,这个时候递归排序就不大适用,所以需要非递归出场。

利用栈来存储区间下标,代码如下:要注意先数组头,后入数组尾。出栈时栈顶的数据为数组尾,在出才为头位置下标。

代码如下:

//交换函数
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}//三数取中
int GetMinIndex(int* arr, int left, int right)
{int mid = (left + right) >> 1;if (arr[left] < arr[mid]){if (arr[mid] < arr[right]){return mid;}if (arr[left] < arr[right] && arr[right] < arr[mid]){return right;}return left;}else//arr[left] >= arr[mid]{if (arr[left] < arr[right]){return left;}if (arr[mid] < arr[right] && arr[right] < arr[left]){return right;}return mid;}
}//快排非递归
void QuickSort(int* arr, int n)
{ST st;StackInit(&st);//把左右区间压栈,先压右边StackPush(&st, n - 1);//后压左边StackPush(&st, 0);//只要栈不为空,就继续分割排序while (!StackEmpty(&st)){//从栈里面取出左右区间int left = StackTop(&st);StackPop(&st);int right = StackTop(&st);StackPop(&st);int index = GetMinIndex(arr, left, right);//因为我们下面的逻辑都是把第一个数作为key,//为了避免改动代码,这里我们直接交换就可以Swap(&arr[left], &arr[index]);//开始单趟排序int begin = left;int end = right;int pivot = begin;int key = arr[begin];while (begin < end){//end开始找小while (begin < end && arr[end] >= key){end--;}arr[pivot] = arr[end];pivot = end;//begin开始找大while (begin < end && arr[begin] <= key){begin++;}arr[pivot] = arr[begin];pivot = begin;}pivot = begin;arr[pivot] = key;//区间分为[left,pivot-1]pivot[pivot+1,right]//利用循环继续分割区间//先入右子区间if (pivot + 1 < right){//说明右子区间不止一个数//先入右边边界StackPush(&st, right);//再入左边边界StackPush(&st, pivot+1);}//再入左子区间if (left < pivot-1){//说明左子区间不止一个数//先入右边边界StackPush(&st, pivot-1);//再入左边边界StackPush(&st, left);}	}StackDestory(&st);
}

五、时间复杂度 

快速排序的时间复杂度:

最坏情况下,时间复杂度是O(n^2); (逆序)

最优情况下,时间复杂度是O(nlogn);

平均时间复杂度是O(nlogn);

快速排序是时间复杂度:O(logn)

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

免费的AI写作软件-智能AI写作工具

我们要谈的话题是AI写作&#xff0c;尤其是免费AI写作&#xff0c;以及147SEOAI写作免费工具。您是否曾经为了创作文章而感到煞费苦心&#xff1f;是否一直在寻找一种能够轻松生成高质量文章的方法&#xff1f; 147GPT批量文章生成工具​www.147seo.com/post/2801.html​编辑ht…

Flink TaskManger 内存计算实战

Flink TaskManager内存计算图 计算实例 案例一、假设Task Process内存4GB。 taskmanager.memory.process.size4096m 先排减JVM内存。 JVM Metaspace 固定内存 256mJVM Overhead 固定比例 process * 0.1 4096 * 0.1 410m 得到 Total Flink Memory 4096-256-410 3430m 计…

求生之路2服务器搭建插件安装及详细的游戏参数配置教程windows

求生之路2服务器搭建插件安装及详细的游戏参数配置教程windows 大家好我是艾西&#xff0c;最近研究了下 l4d2&#xff08;求生之路2&#xff09;这款游戏的搭建以及架设过程。今天就给喜欢l4d2这款游戏的小伙伴们分享下怎么搭建架设一个自己的服务器。毕竟自己当服主是热爱游…

华为云云耀云服务器L实例评测|redis漏洞回顾 MySQL数据安全解决 搭建主从集群MySQL 相关设置

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到过MySQL数据库被攻击的情况&#xff0c;数据丢失&#xff0c;还好我有几份备份&#xff0c;没有造成太大的损失&#xff1b;后来有发现Redis数据库被攻击的情况&#xff0c;加入了redis密…

基于springboot+vue的校园外卖服务系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【Vue+Element-UI】实现登陆注册界面及axios之get、post请求登录功能实现、跨域问题的解决

目录 一、实现登陆注册界面 1、前期准备 2、登录静态页实现 2.1、创建Vue组件 2.2、静态页面实现 2.3、配置路由 2.4、更改App.vue样式 2.5、效果 3、注册静态页实现 3.1、静态页面实现 3.2、配置路由 3.3、效果 二、axios 1、前期准备 1.1、准备项目 1.2、安装…

原生HTML实现marquee向上滚动效果

实现原理&#xff1a;借助CSS3中animation动画以及原生JS克隆API <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /…

Northstar 量化平台

基于 B/S 架构、可替代付费商业软件的一站式量化交易平台。具备历史回放、策略研发、模拟交易、实盘交易等功能。兼顾全自动与半自动的使用场景。 已对接国内期货股票、外盘美股港股。 面向程序员的量化交易软件&#xff0c;用于期货、股票、外汇、炒币等多种交易场景&#xff…

OpenCV中的HoughLines函数和HoughLinesP函数到底有什么区别?

一、简述 基于OpenCV进行直线检测可以使用HoughLines和HoughLinesP函数完成的。这两个函数之间的唯一区别在于,第一个函数使用标准霍夫变换,第二个函数使用概率霍夫变换(因此名称为 P)。概率版本之所以如此,是因为它仅分析点的子集并估计这些点都属于同一条线的概率。此实…

php文件上传功能(文件上传)

实现文件上传是Web开发中常用的功能之一&#xff0c;而PHP也是支持文件上传的。那么&#xff0c;下面我们就来介绍一下常用的PHP实现文件上传的方法。 使用HTML表单实现文件上传 HTML表单是Web开发中最基本的元素之一&#xff0c;它可以接收用户输入的数据&#xff0c;并通过…

论文阅读_大语言模型_Llama2

英文名称: Llama 2: Open Foundation and Fine-Tuned Chat Models 中文名称: Llama 2&#xff1a;开源的基础模型和微调的聊天模型 文章: http://arxiv.org/abs/2307.09288 代码: https://github.com/facebookresearch/llama 作者: Hugo Touvron 日期: 2023-07-19 引用次数: 11…

C语言数组和指针笔试题(四)(一定要看)

目录 二维数组例题一例题二例题三例题四例题五例题六例题七例题八例题九例题十例题十一 结果 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个人主页 &#x1f978;&#x1f978;&#x1f978;C语言 &#x1f43f;️…

SWC 流程

一个arxml 存储SWC &#xff08;可以存多个&#xff0c;也可以一个arxml存一个SWC&#xff09;一个arxml 存储 composition &#xff08;只能存一个&#xff09;一个arxml 存储 system description (通过import dbc自动生成system) 存储SWC和composition的arxml文件分开&#…

如何用好免费的ChatGPT

如何用好免费的ChatGPT 前言ChatGPT使用入口在线体验地址&#xff1a;点我体验 ChatGPT介绍ChatGPT初级使用技巧初级使用技巧&#xff1a;清晰明了的问题表达 ChatGPT中级使用语法中级使用语法&#xff1a;具体化问题并提供背景信息 ChatGPT高级使用高级使用&#xff1a;追问、…

安防监控系统/视频云存储/视频监控平台EasyCVR无法级联上级平台,该如何解决?

安防视频监控系统EasyCVR平台能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也…

Linux三大搜索指令的区别

find&#xff1a;可以在指定的路径下进行文件的搜索 —— 真的在磁盘文件中查找 例如find /usr/bin/ -name ls which 可以在指令路径下&#xff0c;/usr/bin,搜索指令文件 例如&#xff1a;which ls whereis:在系统特定的路径下查找&#xff0c;既可以找到可执行程序&#xff…

设计模式之观察者(发布订阅)模式

观察者模式定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时&#xff0c;会通知所有观察者对象&#xff0c;使它们能够自动更新自己 class Program{static void Main(string[] args){ConcreteSubject concreteSu…

字符串函数

目录 一、求字符串长度 strlen 用法&#xff1a; 注意&#xff1a; 用例&#xff1a; 二、长度不受限制的字符串函数 strcpy 用法&#xff1a; 注意&#xff1a; 用例: strcat 用法&#xff1a; 注意&#xff1a; 用例&#xff1a; strcmp 用法&#xff1a; 三…

Vue系列(三)之 基础语法下篇【事件处理,表单综合案例,组件通信】

一. 事件处理 在 Vue.js 中&#xff0c;v-on 指令被用于监听 DOM 事件&#xff0c;并在事件触发时执行相应的方法&#xff0c;这些方法就是事件处理器。v-on 指令有简写形式 &#xff0c;例如 click"handleClick" 会监听点击事件并执行 handleClick 方法。 事件处理…