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

    package com.leaf.hadoop.second; import java.util.Random; import org.apache.hadoop.conf.Configuration ...

  2. linux下内存

    MMU由一个或一组芯片组成.其功能是把逻辑地址映射为物理地址,进行地址转换(MMU是CPU的一部分) 机器指令仍然用逻辑地址指定一个操作数的地址或一条指令的地址 每个逻辑地址都由一个段选择符(16位) ...

  3. 【SQLServer】Microsoft SQL Baseline Checklist

    今天调查了Microsoft SQL Baseline Checklist中的下面几个问题. Hide Instances Extended Store Procedures Maximum Numb ...

  4. vscode 折叠所有区域

  5. HDU 1875 畅通project再续 (最小生成树 水)

    Problem Description 相信大家都听说一个"百岛湖"的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其它的小岛时都要通过划小船来实现. 如今政府决定大力发展百岛 ...

  6. VueJS实现双向数据绑定:v-model

    HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <titl ...

  7. [转]Linux shell中的那些小把戏

    我日常使用Linux shell(Bash),但是我经常忘记一些有用的命令或者shell技巧.是的,我能记住一些命令,但是肯定不会只在特定的任务上使用一次,所以我就开始在我的Dropbox账号里用文本 ...

  8. java类库中的设计模式

    原帖:http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns 提问:我正在学习GoF的<设计模式&g ...

  9. Java 线程第三版 第五章 极简同步技巧 读书笔记

    一.能避免同步吗? 取得锁会由于下面原因导致成本非常高:     取得由竞争的锁须要在虚拟机的层面上执行很多其它的程序代码.     要取得有竞争锁的线程总是必须等到锁被释放后. 1. 寄存器的效应 ...

  10. H5缓存机制学习记录

    参考文章:http://mp.weixin.qq.com/s?__biz=MTEwNTM0ODI0MQ==&mid=404724239&idx=1&sn=e0a2887f9ff ...