<算法笔记>关于快速排序的算法优化排序(顺便给百度百科纠个错)
快速排序是排序算法之中的基本中的基本,虽然越来越多的接口函数将快速排序“完美的封装了起来”,比如C++中的qsort或者<algorithm>中的sort(与stable_sort相对应),但是深入思考,关于快速排序的优化你可曾想过?:-P
(一)经典快速排序
首先我们来看一下这个百度百科之中的快速排序版本

在上面这张图中,我们一边纠错一边复习下基本的快速排序,基本快速排序的函数体可以明确分为三个块:
1.调整块,根据对称轴pivot(一般选取第一个)从数组的前后两端向中间扫描,pivot作对称轴的同时也是一个哨兵,需要先把哨兵的值保存下来然后进行调换直到完成划分。每次循环注意到左端和右端只能有一次赋值的过程。
2.3.分别向前向后递归。
int tmpL=low;
int tmpR=high;
int tmpV=arr[low];
while(tmpL<tmpR){
while(tmpL<tmpR&&arr[tmpR]<=tmpV)tmpR--;
arr[tmpL]=arr[tmpR];
while(tmpL<tmpR&&arr[tmpL>=tmpV])tmpL++;
arr[tmpR]=arr[tmpL];
}
而在我给出的百度百科的算法中首先是把pivot耿直地写成了povit(可以忽略哈哈何厚铧),然后是一个很严肃的问题,关于代码的格式,要是百科编者不屑于写这种简单的代码的话可以不写嘛,或者再动一动写个花括号也就没事了,总而言之这段代码是不可能被新手/编译器看懂的!
在基本的几种算法之中,快速排序的运行速度是最快的,但是也是不稳定的,也许有的人会说堆排序运行速度理论上不比快速排序慢,但是其实不然,这和计算机部件中cache的命中率有关,堆排序需要在也许很广的地址空间里面不停地进行随机访问。
(二)三路快速排序
三路快速排序与经典快速排序不同之处在于划分部分,也就是函数的第一块。首先我们来看一下经典快速排序的划分过程的示意图:

每一次循环的过程中会有前后两次扫描每次扫描后最多只能进行一次交换。再看三路快速排序的划分过程示意图:

三路快速排序的过程实质上也是一次两端向扫描的过程,但这是一种稳定的排序方法,其核心思想依然是“DIVIDE & CONQUER”,但是和堆排序和选择排序一样整个排序的过程是个
"整理后区"的成长过程,每次的递归过程之中我们根据当前访问到的元素和对称轴的值的比对进行三路分支:
1.当当前元素小与对称轴时,将前端标志low和当前元素进行交换,两个索引值都自加1(前端标志之前的元素都是小于对称轴的元素)
2.当当前元素大于对称轴时,将当前元素和后端标志high进行交换,只将后端标志自减1(后端标志之后的元素都是大于对称轴的元素,当前索引不变以判断这个交换过来的值应划分在哪一部分)
3.当当前元素和对称轴相等的时候,当前索引自加1
代码如下:
template<typename T> ////Operator Overriding Concerned
void tri-qsort(int low,int high,vector<T> v){
if(low>=high)return;////Recurrence Ending
else{
int tmpL=low;
int tmpR=high;
int index=low+;
int pivot=v[i]
while(index<=tmpR){
if(index<pivot) swap(v[index++],v[tmpL++]);
else if(index>pivot) swap(v[index],v[tmpR--]);
else index++;
}////Partition Complete
tri-qsort(low,lt-);
tri-qsort(gt+,hight);
}
(三)双基准快速排序算法
这个双基准快速排序是我最推荐的,虽然双基准快速排序效率在理论上和其他版本的快速排序是基本一样的,但是在处理重复数据时双基准快速排序会有独特的优越性,但是时间复杂度的变化幅度会比较大。
双基准快速排序并不是简单意义上的将整个数据割为两端,交由两个不同的pivot去处理。双基准快速排序是在三路快速排序的基础之上进行的,如下图所示:

双基准排序要做的事情从宏观上来看有两个:(前提约束对称轴1小于对称轴2)
1.整理比对称轴1小的元素到前端标记之前
2.整理比对称轴2大的元素到后端标记之后
那么中间剩下的区域就是比对称轴1大而比对称轴2小的元素,所以我们要做的事情是每次递归之前改变这段数据的对称轴(最前最后两个元素),代码如下:
template<typename T>
void dual-qsort(int low,int high,vector<T> v){
if(low>high)swap(low,high);
int pivotL=low;
int pivotR=high;
int tmpL=low;
int tmpR=high;
int index=low+;
while(index<=tmpR){
if(v[index]<pivotL)swap(v[index++],v[tmpL++]);
else if(v[index]>pivotR)swap(v[index],v[tmpR--]);
else index++;
}
swap(v[--tmpL],v[low]);
swap(v[++tmpR],v[high]);
dual-qsort(low,tmpL-,v);
dual-qsort(tmpL+,tmpR-,v);
dual-qsort(tmpR+,high,v);
}
<算法笔记>关于快速排序的算法优化排序(顺便给百度百科纠个错)的更多相关文章
- 算法笔记_015:快速排序(Java)
目录 1 问题描述 2 解决方案 2.1 快速排序原理简介 2.2 具体编码 1 问题描述 给定一组数据,使用快速排序得到这组数据的非降序排列. 2 解决方案 2.1 快速排序原理简介 引用自百度百科 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)
Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...
- 常见排序算法总结:插入排序,希尔排序,冒泡排序,快速排序,简单选择排序以及java实现
今天来总结一下常用的内部排序算法.内部排序算法们需要掌握的知识点大概有:算法的原理,算法的编码实现,算法的时空复杂度的计算和记忆,何时出现最差时间复杂度,以及是否稳定,何时不稳定. 首先来总结下常用内 ...
- javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法)
javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法) 一.快速排序算法 /* * 这个函数首先检查数组的长度是否为0.如果是,那么这个数组就不需要任何排序,函数直接返回. * ...
- 算法笔记(c++)--桶排序题目
算法笔记(c++)--桶排序 记得题目是排序,输入n个1-1000的数字然后去重然后排序. 桶排序没毛病 #include<iostream> using namespace std; i ...
- 算法笔记_023:拓扑排序(Java)
目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进 ...
- 排序算法四:快速排序(Quicksort)
快速排序(Quicksort),因其排序之快而得名,虽然Ta的平均时间复杂度也是O(nlgn),但是从后续仿真结果看,TA要比归并排序和堆排序都要快. 快速排序也用到了分治思想. (一)算法实现 pr ...
- 算法笔记_014:合并排序(Java)
1 问题描述 给定一组数据,使用合并排序得到这组数据的非降序排列. 2 解决方案 2.1 合并排序原理简介 引用自百度百科: 合并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Div ...
随机推荐
- PropertyGrid—属性类别排序
属性默认按照字母顺序排序,有时,我们想要按自定义的顺序排序 这个工具类可以把每个属性类别里的属性排序,但是不能把属性类别排序. 为属性类添加属性:[TypeConverter(typeof(Prope ...
- nodejs - 创建服务器(1)
在此之前,确保你已经安装了Node(并且你很会折腾) - 有人说,Java脚本和Java最本质的区别就是一个超会更新,一个死守旧. 如果你没有安装,请去官网下载并且安装:http://nodejs.c ...
- vue prop单向数据流
Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会.这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解. 另外,每次父组件更新时,子组件的所有 pro ...
- Android中Java与web通信
Android中Java与web通信不是新的技术了,在android公布之初就支持这样的方式,2011年開始流行,而这样的模式开发也称作Hybird模式. 这里对android中的Java与web通信 ...
- 让heigh:100%起作用
如何让 height:100%; 起作用 http://www.webhek.com/css-100-percent-height 当你设置一个页面元素的高度(height)为100%时,期望 ...
- Apache上部署Django
0. 部署环境 Ubuntu 14.04 on AliYun Apache 2.4.7 Python 3 [2.7升级3请看http://www.cnblogs.com/manhua/p/423504 ...
- 笔记本中G-Sensor(加速计) M-Sensor 陀螺仪等传感器的区别
1.G-sensor重力传感器 作用 G-sensor中文是加速度传感器的意思(英文全称是Accelerometer-sensor),它能够感知到加速力的变化,加速力就是当物体在加速过程中作用在物体上 ...
- PHP计划任务:如何使用Linux的Crontab执行PHP脚本(转)
我们的PHP程序有时候需要定时执行,我们可以使用ignore_user_abort函数或是在页面放置js让用户帮我们实现.但这两种方法都不太可靠,不稳定.我们可以借助Linux的Crontab工具来稳 ...
- Spring学习十----------Bean的配置之Autowired注解实现
© 版权声明:本文为博主原创文章,转载请注明出处 @Required -@Required注解适用于bean属性的setter方法 -这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在b ...
- android7.x Launcher3源代码解析(3)---workspace和allapps载入流程
Launcher系列目录: 一.android7.x Launcher3源代码解析(1)-启动流程 二.android7.x Launcher3源代码解析(2)-框架结构 三.android7.x L ...