MIT算法导论——第四讲.Quicksort

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记。所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解。(http://v.163.com/special/opencourse/algorithms.html

第四节-------快速排序 Quicksort

这节课的主要内容分为两部分,一部分是介绍快速排序算法,分析其在最好、最坏以及最好最差交替出现情况下的算法效率;另一部分则是介绍随机化快排算法,以及分析其算法复杂度。后者也是视频中最精彩的部分。

一、快速排序

快速排序由Tony Hoare在1962年提出,是基于分治思想(Divide-and-conquer)的一种原地排序,但其效率依赖于输入数据的排序状况。所谓原地排序,即指算法的空间复杂度为O(1),它就在原来的数据区域内进行重排。就像插入排序一样,就在原地完成排序。但是归并排序就不一样,它则需要额外的空间来进行归并排序操作。

如下图所示是快速排序中的分治法思想。

由上图可以知道,快速排序里面最关键的就是第一步:分化(Partition)的步骤,这是该算法处理问题的核心。所以我们可以把快排看成是递归地划分数组,就想归并排序是递归地合并数组一样。关于Paritition的具体算法,目前有好几种,其伪代码稍有不同但是它们的原理都是一样的。当然最重要的一点是它们的算法复杂度都是线性的,也就是O(n)。下面是快排的递归伪代码。

当然上面只是一个核心的递归代码。一个让快排运行更快的方法时调整这里的代码,找到适合元素数目较少的特别的算法。比如说,只剩下5个元素,你已经知道了一些代码来高效地排序5个元素,那么用那个特别的算法来替代这里的递归就会好一些。还有一些其他的办法,譬如说这是尾递归的代码,那么就可以使用一些尾递归的优化等等。。。

接下来分析快排的算法效率,在分析中假设所有的元素都是不同的。当重复元素存在时,这里的代码运行的就不是很好,但是Hoare最初的分划方法在待排序的元素中有重复的情况下更为高效。有时间的时候去看一下那个方法,它使用一个更加复杂的不变量来实现分划过程,但是本质上是一样的。

1、最坏情况下分析

那怎样的情况算是快速排序的最坏情况呢?当然是当输入序列是正序或者是反序的时候,因为这时候分划总是围绕着最大的或者是最小的元素进行,那么造成的现象就是分划的另外一边总是没有元素,这样就无法利用递归来提高算法运算的效率。

那么,在这种情况下,快排的算法效率递归式如下图所示,易知这时的效率是Θ(n^2)。

2、最优情况下分析

我们当然没有办法保证输入序列能够满足快排的最优情况,但是我们可以这样直观地来理解:如果我们足够幸运,Partition每次分划的时候正好将数组划分成了两个相等的子数组。那么这种情况下的递归分析式如下图所示。

这显然是我们想要的结果。那么当Partition的时候达不到均等地划分,如果两个子数列划分的比例是1:9呢?

为了解这个递归式,主方法是派不上用场了。这时候搬出总是能够有效的分析树,如下图所示。

综上所述,可以知道快排在最优情况下的算法效率是Θ(nlgn)。

3、最坏与最优交替出现情况下分析

上面我们分析了最好与最坏情况下的算法效率,那么更加普遍的情况是,当最坏情况与最优情况同时都有出现时的算法效率呢?我们假设算法中最坏与最优情况交替出现,那么算法的效率分析如下图所示。

可以得知,在这样的情况下我们也还是幸运的,得到的算法效率与最优情况下的效率一样。那么我们如何保证我们总是幸运的呢?这也是随机化快速排序需要解决的问题。

二、随机化快速排序

我们已经知道,若输入本身已被排序,那么对于快排来说就糟了。那么如何避免这样的情况?一种方法时随机排列序列中的元素;另一种方法时随机地选择主元(pivot)。这便是随机化快速排序的思想,这种快排的好处是:其运行时间不依赖于输入序列的顺序。也就是说我们不再需要对输入序列的分布作任何假设,没有任何一种特定的输入序列能够使算法的效率极低。最不幸运的情况有可能会发生,但是也是因为随机数产生器的原因,不是因为输入序列的原因。

这里的办法是随机地选择主元。如下图所示是随机化快速排序的算法效率递归表达式。

其中,X(k)是一个指示器随机变量,用来简化上述递归式中的复杂度。

因此,计算随机化算法的算法效率就演变成了计算上述含有指示器随机变量的递归式的期望值,具体过程如下图所示。

得到如上图所示的递归式后,如何求解成了一个问题。这里用的方法是替换法(Substitution method)。

这样,就得到了随机化快排的算法效率是Θ(nlgn)。

在实践中,快速排序是一个很好的算法。它虽然不能保证归并排序所提供的在最坏情况下nlgn的运行时间,但是在实践中如果采用随机化快速排序算法,通常比归并排序快3倍以上。当然不可否认的是,确实需要一些编码技巧来使它打到那样的速度,你需要优化基础情况以及其他的一些技巧,但是大部分好的算法都是基于快速排序的。

快速排序很好的另一个原因是它在虚拟内存的缓存中性能比较好。

关于Introduction to Algorithms更多的学习资料将继续更新,敬请关注本博客和新浪微博Sheridan

时间: 2024-11-08 22:02:37

MIT算法导论——第四讲.Quicksort的相关文章

MIT算法导论——第七讲.哈希表

从作用上来讲,构建哈希表的目的是把搜索的时间复杂度降低到O(1),考虑到一个长度为n的序列,如果依次去比较进行搜索的话,时间复杂度是θ(n),或者对其先进行排序然后再搜索会更快一些,但这两种方法都不是最快的方法. 哈希表也叫散列表,他通过一个哈希函数H,把要存储的内容取一个键值,经过H的运算,把键值映射到一个有m个槽的表中去,最简单的例子就是手机里存储别人的电话号码,键值就是名字,内容就是电话号码等个人信息.这样的表有一个最大的好处就是一旦要查找某个值,比如说"张三"的电话号码,我们把

MIT算法导论——第一讲.Analysis of algorithm

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解.(http://v.163.com/special/opencourse/algorithms.html) 第一节-------课程简介及算法分析 Analysis of algorithm 算法分析:关于计算机程序在效率和资源利用方面的理论

MIT算法导论——第二讲.Solving Recurrence

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解.(http://v.163.com/special/opencourse/algorithms.html) 第二节-------渐近符号.递归及解法 Solving Recurrence 第二节课的内容比较偏数学化,没有算法方面的知识.但尽管

MIT算法导论——第五讲.Linear Time Sort

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解.(http://v.163.com/special/opencourse/algorithms.html) 第五节-------线性时间排序 Linear Time Sort 这节课的主要内容是分析基于比较的排序能够达到的最快效率以及介绍几种

MIT算法导论笔记

详细MIT算法导论笔记 (网络链接) 第一讲:课程简介及算法分析 第二讲:渐近符号.递归及解法

MIT算法导论——第三讲.The Divide-and-Conquer

本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. Leiserson和Erik Demaine老师的讲解.(http://v.163.com/special/opencourse/algorithms.html) 第三节-------分治法 The Divide-and-Conquer 这节课的主要内容是介绍分治法的思想,以及一些应用分治法思想的

《算法导论》第一讲

首先讲的就是排序问题,也就是在算法中的经典问题,在这一讲中主要讲了两个排序问题,一个是插入排序,一个是归并排序,在这里,并不是将如何去实现这个排序,而是通过这两个排序来学习渐进分析的原理以及其对应的符号. 1:排序问题 对于一个序列 InsertionSort(A,n) //对A[1,2,...n]进行排序 for j<-2 to n do key<-A[j] i<-j-1 while i>0 and A[i] > key do A[i+1] <- A[i] i<

算法导论 第四部分——基本数据结构——第15章:动态规划

前言:动态规划的概念 动态规划(dynamic programming)是通过组合子问题的解而解决整个问题的.分治算法是指将问题划分为一些独立的子问题,递归的求解各个问题,然后合并子问题的解而得到原问题的解.例如归并排序,快速排序都是采用分治算法思想.本书在第二章介绍归并排序时,详细介绍了分治算法的操作步骤,详细的内容请参考:http://www.cnblogs.com/Anker/archive/2013/01/22/2871042.html.而动态规划与此不同,适用于子问题不是独立的情况,也

算法导论第四章分治策略编程实践(二)

在上一篇中,通过一个求连续子数组的最大和的例子讲解,想必我们已经大概了然了分治策略和递归式的含义,可能会比较模糊,知道但不能用语言清晰地描述出来.但没关系,我相信通过这篇博文,我们会比较清楚且容易地用自己的话来描述. 通过前面两章的学习,我们已经接触了两个例子:归并排序和子数组最大和.这两个例子都用到了分治策略,通过分析,我们可以得出分治策略的思想:顾名思义,分治是将一个原始问题分解成多个子问题,而子问题的形式和原问题一样,只是规模更小而已,通过子问题的求解,原问题也就自然出来了.总结一下,大致