快速排序是排序算法之中的基本中的基本,虽然越来越多的接口函数将快速排序“完美的封装了起来”,比如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. 微信开发token验证失败

    遇到token验证时: 1.首先检验是否是80端口或443端口,能否接收到微信的响应信息,如果使用域名,域名要备注,否则接收不到响应信息: 2.其次判断是否能正常echo $echoStr,之前不能有 ...

  2. 2016.11.29 activiti实战--第19章--统一身份管理(含自定义用户与数组的实现)

    学习资料:<Activiti实战> 第十九章 统一身份管理 本章讲解如何统一业务系统与activiti的用户管理系统. 第5章的时候已经讲解过activiti的用户与组.一般来说业务系统都 ...

  3. 从头认识java-14.2 进一步了解数组

    这一章节我们来全面了解一下数组. 1.数组在初始化之前.我们不能使用他的引用来做不论什么事情. package com.ray.ch14; public class Test { public sta ...

  4. vue组件class绑定

    当在一个自定义组件上使用 class 属性时,这些类将被添加到该组件的根元素上面.这个元素上已经存在的类不会被覆盖. 例如,如果你声明了这个组件: Vue.component('my-componen ...

  5. Node.js学习笔记(6)——使用Express创建一个工程

    前提是搭建好了环境,node,npm,express:(推荐全局安装) 开始用express创建一个基础工程: express –t ejs microblog 进入文件夹之后 npm-install ...

  6. 多系统启动光盘制作---WIN7+WinXP+老毛桃PE工具箱

    1.工具: ⑴ Windows 7 ISO: ⑵ Windows XP ISO: ⑶ 老毛桃U盘启动盘制作工具V2013 制作得的ISO (含PE.DOS等): ⑷ UltraISO.EasyBoot ...

  7. robotframe使用之滚动条

    方法一:Excute JavaScript window.scrollTo(0,document.body.scrollHeight); 方法二:Execute javascript document ...

  8. python thrift hbase安装连接

    默认已装好 hbase,我的版本是hbase-0.98.24,并运行 python 2.7.x 步骤: sudo apt-get install automake bison flex g++ git ...

  9. 双向数据绑定---AngularJS的基本原理学习

    Angular JS (Angular.JS) 是一组用来开发Web页面的框架.模板以及数据绑定和丰富UI组件.它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作. AngularJS非 ...

  10. Hibernate demo之使用注解

    1.新建maven项目 testHibernate,pom.xml <?xml version="1.0" encoding="UTF-8"?> & ...