【DS】排序算法之快速排序(Quick Sort)
一、算法思想
快速排序,顾名思义,效率比较于其他算法,效率比较高。《算法导论》也专门对其进行讲解。其算法设计使用分治思想,如下:
1)从数组A[p...r]中选择一个元素,将数组划分成两个子数组:A[p...q-1]和A[q+1...r],使得A[p...q-1]中的元素全部小于等于A(q),使得A[q+1...r]中的元素全部大于A(q);
2)通过递归调用快速排序,分别对A[p...q-1]和A[q+1...r]排序;
3)因为两个子数组是就地排序,因此它们的合并不需要操作,整个数组A[p...r]已经排序;
二、算法示意图

图中所示只是代表一次分的过程,其中红色的4代表选中的用于分割的数组元素,灰色部分代表待排序的过程,黄色部分代表小于等于选中元素的数组元素,蓝色部分则代表大于选中元素的数组元素。解释一下这一次过程的形成:
第一行表示待排序的数组,其中默认选择待排序数组的最后一个元素作为中间元素进行分割。第二行我们看第一个元素,2比4小,不需要操作,第三行看8,8比4大,也不需要操作,因为由图可以看出来,第三行正好是‘≤4’,‘>4’,待排序元素,选择元素这样一个序列;第四行看7,发现7>4,也不需要操作,第五行看1,1这个时候比4小,应该和2放在一起,则最快的方法是和‘>4’序列块的第一个元素交换,因此将滴4行元素的1和8交换就得到第五行;同理,第六行看的是3,将第五行的3和7交换就得到第六行。如此下去,直到倒数第二行,已经没有待排序元素了。这个时候,将交换元素和‘>4’序列块的第一个元素交换,即4和8交换,就形成最后一行,最终的形式是‘≤选中元素(4)’,选择元素,‘>选中元素(4)’这样一个序列。然后再对‘≤选中元素(4)’和‘>选中元素(4)’两个序列块,即最后一行的黄色部分和蓝色部分分别执行相同过程,最终完成排序。
从描述中可以看到:
1)选择最后一个元素作为选择元素,可以最大程度降低元素交换的复杂性;
2)如果遍历找到比选中元素小或者相等的元素,则需要和‘>选中元素’序列块的第一个元素交换,这样就可以和‘≤选中元素’的序列块最快的接合到一起;
3)如果遍历找到比选中元素大的元素,则不需要操作;
4)为了快速的交换,我们需要对序列添加多个指针:指向‘≤选中元素’的序列块的第一个和最后一个,指向选中元素;
三、Java代码
先来看看一种简单直接的实现:
//@wiki
public class Quicksort {
public static final Random RND = new Random(); private static void swap(Object[] array, int i, int j) {
Object tmp = array[i];
array[i] = array[j];
array[j] = tmp;
} private static <E> int partition(E[] array, int begin, int end, Comparator<? super E> cmp) {
int index = begin + RND.nextInt(end - begin + 1);
E pivot = array[index];
swap(array, index, end);
for (int i = index = begin; i < end; ++ i) {
if (cmp.compare(array[i], pivot) <= 0) {
swap(array, index++, i);
}
}
swap(array, index, end);
return (index);
} private static <E> void qsort(E[] array, int begin, int end, Comparator<? super E> cmp) {
if (end > begin) {
int index = partition(array, begin, end, cmp);
qsort(array, begin, index - 1, cmp);
qsort(array, index + 1, end, cmp);
}
} public static <E> void sort(E[] array, Comparator<? super E> cmp) {
qsort(array, 0, array.length - 1, cmp);
} }
这段代码应该比较好懂,因为和上面的解说基本一样,qsort函数是一个递归函数,其中用到一个partition函数进行分割。这段代码有以下几个需要注意的地方:
1)使用了泛型和Comparator,这样更具扩展性;
2)注意12~14行,前面解说中我们默认选择的是待排序序列的最后一个元素,但是这里不是,这里是随机产生一个选择元素,然后为了交换元素的方便,首先将这个选择元素交换到序列的最后面去,划归到解说中的形式;
四、算法复杂度
最坏情况划分:在划分过程中产生两个区域,分别包含n-1个元素和1和0元素的时候(这个时候选中的元素是序列中最大或者最小的元素)。假设算法的每一次递归调用的时候都出现了这种不对称的划分,划分的时间代价为θ(n)。因为对一个大小为0的数组进行递归调用以后,返回T(0)=θ(1),所以算法的运行时间可以递归的表示为:
T(n) = T(n-1) + θ(n) + θ(1)
利用替换法,可以比较直接的证明其解为T(n)=θ(n^2)。
最好情况划分:即划分的时候,序列正好划分为两半,有时候序列元素个数为奇数,不能相等,则左右可以相差1,这个时候,其表达式为:
T(n) ≤ 2T(n/2) + θ(n)
可以解得递归式的解为T(n)=O(nlogn)。
【DS】排序算法之快速排序(Quick Sort)的更多相关文章
- 基础排序算法之快速排序(Quick Sort)
快速排序(Quick Sort)同样是使用了分治法的思想,相比于其他的排序方法,它所用到的空间更少,因为其可以实现原地排序.同时如果随机选取中心枢(pivot),它也是一个随机算法.最重要的是,快速排 ...
- Java中的经典算法之快速排序(Quick Sort)
Java中的经典算法之快速排序(Quick Sort) 快速排序的思想 基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小, 然后再按此方法对 ...
- 基础算法之快速排序Quick Sort
原理 快速排序(Quicksort)是对冒泡排序的一种改进. 从数列中挑出一个元素,称为"基准"(pivot); 排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的 ...
- [算法] 快速排序 Quick Sort
快速排序(Quick Sort)使用分治法策略. 它的基本思想是:选择一个基准数,通过一趟排序将要排序的数据分割成独立的两部分:其中一部分的所有数据都比另外一部分的所有数据都要小.然后,再按此方法对这 ...
- Python之排序算法:快速排序与冒泡排序
Python之排序算法:快速排序与冒泡排序 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/7828610.html 入坑(简称IT)这一行也有些年头了,但自老师 ...
- 排序算法之快速排序Java实现
排序算法之快速排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb 选择排序:http://t.cn/hros6e 插入排序:ht ...
- 快速排序Quick sort
快速排序Quick sort 原理,通过一趟扫描将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归 ...
- Java常见排序算法之快速排序
在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...
- 常用排序算法之——快速排序(C语言+VC6.0平台)
经典排序算法中快速排序具有较好的效率,但其实现思路相对较难理解. #include<stdio.h> int partition(int num[],int low,int high) / ...
- Java排序算法之快速排序
Java排序算法之快速排序 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排序由C. A. R. Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分 ...
随机推荐
- 软件工程第二次作业(JUnit的使用)
初次使用JUnit 感谢学习资源Junit使用的超简单介绍源 一.开发环境及界面截图: 系统 Windows 10 编辑器 eclipse 语言 ...
- C++基础知识(1)
C语言是结构化编程语言(for循环.while循环.do while循环和if else语句),将低级语言的效率.硬件访问能力和高级语言的通用性.可移植性融合在一起. UNIX编译和链接 UNIX用C ...
- CryptoZombies学习笔记——Lesson2
第二课是僵尸猎食,将把app变得更像一个游戏,添加多人模式,建立更多创造僵尸的方法. chapter1 依然是简介 chapter2:映射和地址 映射相当于一个索引,指向不同地址,不同地址存储的数据不 ...
- 关于T/G/M/K
//扫盲贴 K, G, T,都是表数量,只是个数字,在不同的场合下表示的不同.在计算机行业中,这几个量可用来表示数据传输速度和容量,下面分别讨论,希望不了解的朋友不要被某知道上的误解了.如果有什么错误 ...
- PAT甲题题解-1076. Forwards on Weibo (30)-BFS
题目大意:给出每个用户id关注的人,和转发最多的层数L,求一个id发了条微博最多会有多少个人转发,每个人只考虑转发一次.用BFS,同时每个节点要记录下所在的层数,由于只能转发一次,所以每个节点要用vi ...
- Notes of Daily Scrum Meeting(12.17)
我们会尽量安排好时间,在其他作业不受影响的情况下加快项目的进度,在Deadline之前完成Beta阶段的工作. 今天的团队工作总结如下: 团队成员 今日团队工作 陈少杰 调试网络连接,补充后端代码 王 ...
- 浅谈FPGA
浅谈FPGA 前言 生活中永远都不会缺少「 为什么 」,于最近就被合胜学长了,问了一个看似简单却又极具意义的问题,为什么需要FPGA?FPGA与单片机的区别是什么?瞬间刷新了我入门三天FPGA的冲击感 ...
- Mac 绑定Gitlab或者GitHub帐号,从新生成公钥
1.SSH(Secure Shell)是一种安全协议,在你的电脑与GitLab服务器进行通信时,我们使用SSH密钥(SSH Keys)认证的方式来保证通信安全. 2.创建 SSH密钥,并将密钥中的公钥 ...
- Validform验证时可以为空,否则按照指定格式验证
在使用Validform v5.3.2时(http://validform.rjboy.cn/) 问题:可以为空,但不为空时需要按照指定格式验证数据 查看文档: 5.2.1版本之后,datatype支 ...
- ElasticSearch 2 (34) - 信息聚合系列之多值排序
ElasticSearch 2 (34) - 信息聚合系列之多值排序 摘要 多值桶(terms.histogram 和 date_histogram)动态生成很多桶,Elasticsearch 是如何 ...