快速排序原理、复杂度分析及C语言实现
2014-11-27 17:12
357 查看
本文作者华科小涛:@http://www.cnblogs.com/hust-ghtao/
,参考《算法导论》,代码借用《剑指offer》
快速排序是一种最坏情况时间复杂度为
分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小。
解决:递归的求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
合并:将子问题的解组合成原问题的解。
对一个典型的子数组A[p..r]进行快速排序的分治过程如下:
分解:数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每一个元素都小于等于A[q],而A[q+1..r]中的每个元素都大于A[q]。其中计算下标q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
合并:因为子数组都是原址排序的,所以不需要合并操作。
,为了排序数组A的全部元素,初始调用QUICKSORT(A, 1, A.length)。
其中最关键的部分就是数组的划分PARTITION,它实现了对子数组A[p..r]的原址重排。伪代码如下:
。
这里的PARTITION程序选择x=A[r]作为主元,并围绕着它来划分数组。
随着程序的增加,数组被划分成4个区域,如下图所示:
其中:
A[p..i]上的所有值都小于等于x;
A[i+1..j-1]区间的所有值都大于x;
A[j..r-1]是还未扫描的元素,可能属于任何一种情况;
A[r]=x。
指针 i 一直指向小值数组的最后一个元素,j指向大值数组末尾的下一个元素。
PARTITION的一次迭代过程中会出现两种情况:
(a)如果A[j]>x,需要做的只是将j值加1:
(b)A[j]<=x,则将i值加1,并交换A[i]和A[j],在将j值加1,使循环不变量保持不变。
。
在PARTITION的最后,将主元与最左的大于x的元素进行交换,就可以将主元移动到它在数组中的正确位置,并返回主元的新下标。
可以解得:
。
所以,如果在算法的每一层递归上,划分都是最大程度不平衡的,那么算法的时间复杂度为:
。
可以解得:
。
另外,只要是划分是常数比例的,甚至好的和差(极不平衡)的划分交替出现时,快速排序算法和全是好的划分时一样,仍然是
。
从A[p..r]中随机选择一个元素作为主元。为了达到这一目的,首先将A[r]与从A[p..r]随机选择的元素交换。通过对序列p..r随机抽样保证主元素
x=A[r]是等概率从r-p+1个元素中选取的。
下面是RANDOMIZED-PARTITION和RANDOMIZED-QUICKSORT的伪代码:
在使用RANDOMIZED-PARTITION,输入元素互异的情况下,快速排序算法的期望运行时间为
。
[/code]
QUICKSORT:
[/code]
,参考《算法导论》,代码借用《剑指offer》
快速排序是一种最坏情况时间复杂度为
的排序算法。虽然最坏情况的时间复杂度很差,在在实际应用中是最好的选择,平均性能很好:期望时间复杂度
,而且
隐含的常数因子非常小。另外,它还能够进行原排序,在虚拟环境中也能很好工作。基于随机抽样的快速排序算法,在输入元素互异的情况下,期望运行时间为
。
1.基本思想
快速排序利用了分治策略。分治策略可以分为3个步骤:分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小。
解决:递归的求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
合并:将子问题的解组合成原问题的解。
对一个典型的子数组A[p..r]进行快速排序的分治过程如下:
分解:数组A[p..r]被划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每一个元素都小于等于A[q],而A[q+1..r]中的每个元素都大于A[q]。其中计算下标q也是划分过程的一部分。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]进行排序。
合并:因为子数组都是原址排序的,所以不需要合并操作。
2.详细过程
快速排序的伪代码如下:,为了排序数组A的全部元素,初始调用QUICKSORT(A, 1, A.length)。
其中最关键的部分就是数组的划分PARTITION,它实现了对子数组A[p..r]的原址重排。伪代码如下:
。
这里的PARTITION程序选择x=A[r]作为主元,并围绕着它来划分数组。
随着程序的增加,数组被划分成4个区域,如下图所示:
其中:
A[p..i]上的所有值都小于等于x;
A[i+1..j-1]区间的所有值都大于x;
A[j..r-1]是还未扫描的元素,可能属于任何一种情况;
A[r]=x。
指针 i 一直指向小值数组的最后一个元素,j指向大值数组末尾的下一个元素。
PARTITION的一次迭代过程中会出现两种情况:
(a)如果A[j]>x,需要做的只是将j值加1:
(b)A[j]<=x,则将i值加1,并交换A[i]和A[j],在将j值加1,使循环不变量保持不变。
。
在PARTITION的最后,将主元与最左的大于x的元素进行交换,就可以将主元移动到它在数组中的正确位置,并返回主元的新下标。
3.性能分析
快速排序的运行时间依赖于划分是否平衡,而平衡与否又依赖于用于划分的元素。3.1 最坏情况划分
当划分产生的两个子问题分别包含了n-1个元素和0个元素,这是极不平衡的划分。假设算法的每一次递归都出现了这种不平衡的划分,算法运行时间的递归式可以表示为:可以解得:
。
所以,如果在算法的每一层递归上,划分都是最大程度不平衡的,那么算法的时间复杂度为:
。
3.2 平均情况
在最平衡的划分中,PARTITION得到的两个子问题的规模都不大于n/2。算法运行时间的递归式为:可以解得:
。
另外,只要是划分是常数比例的,甚至好的和差(极不平衡)的划分交替出现时,快速排序算法和全是好的划分时一样,仍然是
。
4.随机化版本
在算法中引入随机性,使得算法对所有的输入都能获得较好的期望性能。从A[p..r]中随机选择一个元素作为主元。为了达到这一目的,首先将A[r]与从A[p..r]随机选择的元素交换。通过对序列p..r随机抽样保证主元素
x=A[r]是等概率从r-p+1个元素中选取的。
下面是RANDOMIZED-PARTITION和RANDOMIZED-QUICKSORT的伪代码:
在使用RANDOMIZED-PARTITION,输入元素互异的情况下,快速排序算法的期望运行时间为
。
6.代码实现
RANDOMIZED-PARTITION:[code] int Partition(int data[], int length, int start, int end)
{
if (data == NULL||length<=0||start<0||end>=length)
{
throw new std::exception("Invalid Parameters");
}
int index = RandomInRange(start, end);
Swap(&data[index], &data[end]);
int small = start - 1;
for (index = start; index < end;++index)
{
if (data[index] < data[end])
{
++small;
if (small!=index)
{
Swap(&data[index], &data[small]);
}
}
}
++small;
Swap(&data[small], &data[end]);
return small;
}
[/code]
QUICKSORT:
[code] void QuickSort(int data[], int length, int start, int end)
{
if (start == end)
{
return;
}
int index = Partition(data, length, start, end);
if (index >start)
{
QuickSort(data, length, start, index-1);
}
if (index<end)
{
QuickSort(data, length, index + 1, end);
}
}
[/code]
相关文章推荐
- 快速排序分析与C语言实现
- 快速排序实现与分析
- c语言实现快速排序
- 快速排序_C语言实现
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 快速排序详解--C语言实现
- 快速排序 原理与实现
- 各种算法的C#实现系列1 - 合并排序的原理及代码分析
- 元素排序几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 快速排序的C语言源代码与分析
- 图解排序算法及C语言实现之 ------ 快速排序:Quick Sort
- C语言调用库函数实现快速排序
- 排序系列--快速排序(实现+复杂度分析)
- C语言实现基本排序算法----排序(直接插入排序,SHELL排序,冒泡排序,快速排序,简单选择排序,堆排序)
- 几种常用的排序算法的分析及java实现(希尔排序,堆排序,归并排序,快速排序,选择排序,插入排序,冒泡排序)
- 快速排序的C语言代码实现
- 位图排序原理及C语言实现(源于《编程珠玑》)
- 快速排序的C语言实现及其时间复杂度
- 快速排序 C语言实现
- QuickSort 快速排序的分析与实现