算法导论-快速排序

1、快速排序的描述算法

快速排序是基于分治策略的。对一个子数组A[p…r]快速排序的分治过程的三个步骤为:数组

一、分解函数

数组A[p…r]被划分红两个(可能空)子数组A[p…q-1]和A[q+1…r],使得A[p…q-1]中的每一个元素都小于等于A[q],且小于等于A[q+1…r]中的元素。下标q也在这个划分过程当中进行计算。性能

二、解决ui

经过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]排序。spa

三、合并3d

由于两个子数组就是原地排序的,将它们的合并不须要操做:整个数组A[p…r]已排序。code

 

快速排序的参考代码以下:blog

 1 class Solution
 2 {
 3 public:
 4     void QuickSort(int *a, int length);
 5     void QSort(int *a, int low, int high);
 6     int Partition(int *a, int low, int high);
 7 };
 8 
 9 void Solution::QuickSort(int *a, int length)
10 {
11     QSort(a, 0, length - 1);
12 }
13 
14 void Solution::QSort(int *a, int low, int high)
15 {
16     if (low < high)
17     {
18         int p = Partition(a, low, high);
19         QSort(a, low, p - 1);
20         QSort(a, p + 1, high);
21     }
22 }
23 
24 int Solution::Partition(int *a, int low, int high)
25 {
26     int key = a[high], tmp;
27     int i = low - 1, j;
28 
29     for (j = low; j < high; ++j)
30     {
31         if (a[j] <= key)
32         {
33             i = i + 1;
34 
35             tmp = a[j];            //交换a[j]和a[i]
36             a[j] = a[i];
37             a[i] = tmp;
38         }
39     }
40 
41     tmp = a[high];                //交换a[high]和a[i + 1]
42     a[high] = a[i + 1];
43     a[i + 1] = tmp;
44 
45     return i + 1;
46 }

函数Partition()的另一种直观写法以下:排序

 1 int Solution::Partition(int *a, int low, int high)
 2 {
 3     int key = a[low];
 4     
 5     while (low < high)
 6     {
 7         while (low < high && key <= a[high])
 8         {
 9             --high;
10         }
11         a[low] = a[high];
12 
13         while (low < high && key >= a[low])
14         {
15             ++low;
16         }
17         a[high] = a[low];
18     }
19     a[low] = key;
20 
21     return low;
22 }

2、快速排序的性能

快速排序的运行时间与划分是否对称有关,然后者又与选择了哪个元素来进行划分有关。若是划分是对称的,算法从渐进意义上就与归并排序同样快;若是划分是不对称的,算法从渐进意义上就和插入算法同样慢。函数Partition()在子数组A[p…r]上的运行时间为,其中n=r-p+1。

一、最坏状况划分

最坏状况划分发生在划分过程当中产生的两个区域分别包含n-1个元素和1个0元素的时候。假设算法的每一次递归调用都出现这种不对称划分。划分的时间代价为,对一个大小为0的数组进行递归调用的时间代价为算法的运行时间可表示为:

,解出

所以,若是在算法的每一层递归上,划分都是最大程度不对称的,算法的运行时间就是。从而,快速排序算法的最坏状况运行时间并不比插入排序的更好。例如:当输入数组已经彻底排好序时,快速排序的运行时间为,插入排序的运行时间为

 

二、最佳状况划分

函数Partition()可能作的最平衡的划分中,获得的两个子问题的大小接近n/2。在这种状况下,快速排序运行的速度要快得多。算法的运行时间可表示为:,解出

 

三、平衡的划分

快速排序的平均状况运行时间与其最佳状况运行时间很接近,而不是很是接近于其最坏状况运行时间。例如:假设划分过程老是产生9:1的划分,算法的运行时间可表示为:这一递归式对应的递归树如图:

该树每层代价都是cn,直到在深度处终止。这样快速排序的总代价为

在递归的每一层上按照9:1的比例进行划分,直观上看好像至关不平衡,但从渐进意义上,这与在正中间划分的效果是同样的。事实上按照99:1划分运行时间也为,缘由在于任何一种按照常数比例进行的划分都会产生深度为的递归树,其中每一层的代价为,于是,每当按照常数比例划分时,总的运行时间都是

 

3、结论

一、优势:由于每趟能够肯定不止一个元素的位置,并且呈指数增长,因此特别快。前提:顺序存储结构。

二、改变划分元素的选取方法,至多只能改变算法平均状况下的时间性能,没法改变最坏状况下的时间性能。

三、是一种不稳定的排序算法,是原地排序。

四、对包含n个数的输入数组,最坏运行时间为。虽然这个最坏状况运行时间比较差,但快速排序一般是用于排序的最佳实用选择,由于其平均性能为,且记号中隐含的常数因子很小。在虚拟环境中也能很好地工做。

相关文章
相关标签/搜索