快速排序是排序算法之中的基本中的基本,虽然越来越多的接口函数将快速排序“完美的封装了起来”,比如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);
}

<算法笔记>关于快速排序的算法优化排序(顺便给百度百科纠个错)的更多相关文章

  1. 算法笔记_015:快速排序(Java)

    目录 1 问题描述 2 解决方案 2.1 快速排序原理简介 2.2 具体编码 1 问题描述 给定一组数据,使用快速排序得到这组数据的非降序排列. 2 解决方案 2.1 快速排序原理简介 引用自百度百科 ...

  2. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  3. 学习Java 以及对几大基本排序算法(对算法笔记书的研究)的一些学习总结(Java对算法的实现持续更新中)

    Java排序一,冒泡排序! 刚刚开始学习Java,但是比较有兴趣研究算法.最近看了一本算法笔记,刚开始只是打算随便看看,但是发现这本书非常不错,尤其是对排序算法,以及哈希函数的一些解释,让我非常的感兴 ...

  4. 常见排序算法总结:插入排序,希尔排序,冒泡排序,快速排序,简单选择排序以及java实现

    今天来总结一下常用的内部排序算法.内部排序算法们需要掌握的知识点大概有:算法的原理,算法的编码实现,算法的时空复杂度的计算和记忆,何时出现最差时间复杂度,以及是否稳定,何时不稳定. 首先来总结下常用内 ...

  5. javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法)

    javascript数据结构与算法--高级排序算法(快速排序法,希尔排序法) 一.快速排序算法 /* * 这个函数首先检查数组的长度是否为0.如果是,那么这个数组就不需要任何排序,函数直接返回. * ...

  6. 算法笔记(c++)--桶排序题目

    算法笔记(c++)--桶排序 记得题目是排序,输入n个1-1000的数字然后去重然后排序. 桶排序没毛病 #include<iostream> using namespace std; i ...

  7. 算法笔记_023:拓扑排序(Java)

    目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进 ...

  8. 排序算法四:快速排序(Quicksort)

    快速排序(Quicksort),因其排序之快而得名,虽然Ta的平均时间复杂度也是O(nlgn),但是从后续仿真结果看,TA要比归并排序和堆排序都要快. 快速排序也用到了分治思想. (一)算法实现 pr ...

  9. 算法笔记_014:合并排序(Java)

    1 问题描述 给定一组数据,使用合并排序得到这组数据的非降序排列. 2 解决方案 2.1 合并排序原理简介 引用自百度百科: 合并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Div ...

随机推荐

  1. spring Multiple MongoTemplate

    <!-- 数据环境配置 --> <mongo:repositories base-package="com.my9yu.manager.module.server.repo ...

  2. from: Maven实战(九)——打包的技巧

    from : http://www.infoq.com/cn/news/2011/06/xxb-maven-9-package 要点: 1. 打出可执行的jar包, 2. 自定义打包

  3. 【React Native开发】React Native移植原生Android项目(4)

    ),React Native技术交流4群(458982758),请不要反复加群!欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客左側欢迎微信扫描关注订阅号,移动技术干货,精彩文章 ...

  4. 手动脱Mole Box壳实战总结

    作者:Fly2015 这个程序是吾爱破解脱壳练习第8期的加壳程序,该程序的壳是MoleBox V2.6.5壳,这些都是广告,能够直接无视了.前面的博客手动脱Mole Box V2.6.5壳实战中已经给 ...

  5. 2017.04.20 Adams仿真介绍

    Adams 仿真 | 验证"隐性机器人模型"概念,提高视觉伺服精度 产品:Adams行业:科研优势: 1.Adams 仿真可精确预测机器人的位置和方位 2.仿真在理论工作验证中起着 ...

  6. Web前端开发--JS技术大梳理

    什么是JS      JavaScript是一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语 ...

  7. Log4net日志记录、详细配置(自己使用>)

    log4net库是Apache log4j框架在Microsoft.NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台.文件.数据库等)的工具 1.首先添加对log4net.dll的引 ...

  8. robot framework selenium2library定位

    进行页面元素操作,最麻烦的莫过于元素定位了,经常提示element is not visible 或者element is not exist 下面介绍常见的定位方法和定位中的问题 1 使用name和 ...

  9. 15:取近似值ApproximateValue

    题目描述 写出一个程序,接受一个正浮点数值,输出该数值的近似整数值.如果小数点后数值大于等于5,向上取整:小于5,则向下取整. 输入描述:输入一个正浮点数值 输出描述:输出该数值的近似整数值 输入例子 ...

  10. 优秀JS学习站点

    第一个:电子书类集合站点:http://www.javascriptcn.com/thread-2.html 第二类:移动端博客学习: https://segmentfault.com/a/11900 ...