MIT算法导论-第四讲-快速排序
来源:互联网 发布:好看的网络科幻小说 编辑:程序博客网 时间:2024/05/10 22:39
1.快速排序的描述
快速排序算法采用的分治算法,因此对一个子数组A[p…r]进行快速排序的三个步骤为:
(1)分解:数组A[p…r]被划分为两个(可能为空)子数组A[p…q-1]和A[q+1…r],给定一个枢轴,使得A[p…q-1]中的每个元素小于等于A[q],A[q+1…r]中的每个元素大于等于A[q],q下标是在划分过程中计算得出的。
(2)解决:通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行排序。
(3)合并:因为两个子数组是就地排序,不需要合并操作,整个数组A[p…r]排序完成。
快速排序的伪代码如下
快速排序的代码如下
//对a[start..end]快速排序void QuickSort(int a[], int start, int end) { if (start == end) return; //划分后的基准记录的位置,对a[start..end]做划分 int index = Partition(a, start, end); //int index = PartitionNormal(a, start, end); //int index = PartionRandom(a, start, end); if (index > start) QuickSort(a, start, index - 1); //对左区间递归排序 if (index < end) QuickSort(a, index + 1, end); //对右区间递归排序}
2 最坏、最佳、一般情况的时间复杂度分析
2.1 Worst-Case 分析
当输入的序列是有序的,或者逆序的时候,即划分的一边一直是没有元素。
此时,快排的算法效率递归式以及递归树如下图所示,显然时间复杂度为Θ(n^2)。
2.2 Best-Case 分析
快排划分的最佳情况为,Partition每次分划的时候正好将数组划分成了两个相等的子数组。
递归式为:
时间复杂度为
另一种情况为数组被划分为两个长度不等的子数组,比如两个子数组划分的比例是1:9。
这时,递归式为:
递归树为:
显然,树的最低高度为
树的最高高度为
因此,时间复杂度的范围为:
综上所述,可以知道快排在最佳情况下的算法效率是Θ(nlgn)。
2.3 最佳和最差循环交替情况分析
上面我们分析了最好与最坏情况下的算法效率,那么更加普遍的情况是,当最坏情况与最优情况同时都有出现时的算法效率呢?我们假设算法中最坏与最优情况交替出现,那么算法的效率分析如下所示。
最佳情况时,递归式为:
最差情况时,递归式为:
最差递归式代入最佳递归式得
仍然是最佳情况时的时间复杂度。
一般情况下已第一个元素作为Partition的基准元素的代码如下所示:
//普通划分,已数组第一个元素作为基准元素int PartitionNormal(int a[], int low, int high) { int pivot = a[low]; int i = low - 1; for (int j = low + 1; j <= high; j++) { if (a[j] <= pivot) { i++; int t = a[i]; a[i] = a[j]; a[j] = t; } } a[i + 1] = pivot; return i + 1;}
3 随机化快速排序
我们已经知道,若输入本身已被排序,那么对于快排来说就糟了。那么如何避免这样的情况?
两种解决方案:
1:随机排列序列中的元素;
2:随机地选择基准元素(pivot);
这便是随机化快速排序的思想,这种快排的好处是:其运行时间不依赖于输入序列的顺序。
这里使用第二种方法:随机选择基准元素。如下图所示是随机化快速排序的递归表达式。
随机化快速排序的Partition代码如下所示:
//产生一个 [low,high]之间的随机数int GenerateRandomNum(int low, int high) { if (low < high) return rand() % (high - low + 1) + low; else return low;}void Swap(int& a, int& b) { int t = a; a = b; b = t;}//随机化划分,随机选择数组中的数作为基准元素int RandomPartitionEnd(int a[],int low,int high) { if (low == high) return low; int index = GenerateRandomNum(low, high); int pivot = a[index]; Swap(a[index],a[high]); int i = low-1; for(int j=low;j<high;j++) { if(a[j]<=pivot) { Swap(a[i+1],a[j]); } } Swap(a[i+1],a[high]); return i+1;}
附随机化快速排序的时间复杂度具体证明以及分析如下,我表示这里证明起来很麻烦啊(⊙︿⊙)(⊙︿⊙),这里用到一个重要的工具,那就是指示器随机变量,它为概率与期望之间的转换提供了一个便利的方法,这里给出指示器随机变量I{A}的定义。
给定一个样本空间S和事件A,那么事件A对应的指示器随机变量I{A}定义为
下面介绍随机化版本的快速排序算法,时间复杂度T(n)期望的求解和证明。
1.设指示器随机变量
2.随机化后T(n)可能的取值
3.计算随机化后T(n)的数学期望,这里用到了一个非常机智的技巧,就是使用指示器随机变量将随机化后的T(n)用数学公式归纳出来。如何将指示器随机变量与随机化后的T(n)联系到一起,是证明的关键。
4.计算
5.证明T(n)期望的时间复杂度,这里显然要使用代换法,并且使用了一定的数学技巧求期望的和。
0 0
- MIT算法导论-第四讲-快速排序
- MIT算法导论第四节笔记——快速排序
- MIT算法导论——第四讲.Quicksort
- MIT算法导论——第四讲.Quicksort
- MIT算法导论-第五讲-线性时间排序
- 算法导论MIT第一讲
- 算法导论第四章-快速排序
- MIT算法导论-第一讲-算法分析
- MIT算法导论-第三讲-分治
- MIT:算法导论——4.2快速排序 以及 排序算法时间复杂度分析
- 算法导论——第四章——快速排序
- MIT算法导论学习-Lecture5 排序
- 算法导论-快速排序
- 【算法导论】快速排序
- 算法导论-----快速排序
- 【算法导论】快速排序
- 算法导论:快速排序
- 快速排序--【算法导论】
- HTML文本去除标签
- #if 0 #endif的作用
- SQL使用
- erlang 面试题
- 正则表达式
- MIT算法导论-第四讲-快速排序
- 喷水装置(一)
- 选择图片
- Spring声明式事务管理(基于注解的方式)
- angular实现两个select选择框互相传值
- 41.Android aapt工具
- UIWebview 适配 计算webview高度
- java加载文件路径问题
- leetcode-dungeon-game