快速排序详解

来源:互联网 发布:南京大学大数据实验室 编辑:程序博客网 时间:2024/05/29 04:51

快速排序法详解

快速排序法(QuickSort)是一种非常快的对比排序方法。它也Divide-And-Conquer思想的实现之一。自从其产生以来,快速排序理论得到了极大的改进,然而在实际中却十分难以编程出正确健壮的代码。本文将对快速排序算法的基本理论和编程实践方面做作一个全面的讲解。在本文讲解中,将忽略很多细枝末节,试图给读者形成一个非常具体的快速排序形象。

1.快速排序—基本理论

因为该算法是Divide-And-Conquer思想的一个实现,所以本文将以Divide-And-Conquer思想对其进行分析。首先,假设所要排序的数字存储在数组S中,则该算法的操作可以拆分为两部分:

在S中选出一个元素v;
将S数组分为三个子数组。其中v这个元素单独形成子数组1,比v小的元素形成子数组2,比v大的元素形成自数组3.
分别对子数组2和子数组3进行前两步操作,实现递归排序;
返回时,依次返回S1,V,S2;
该程序具有平均运行时间T(n) = O(nlgn), 最差运行时间T(n) = O(n^2);

下面给出一个简单的排序实例对以上算法进行简单说明:

初始数组为————–> S: 6,10,13,5,8,3,2,11

将第一个元素赋值给v—–>v = 6;

以v为标准将S进行拆分—>[2,5,3],[6],[8,13,10,11] <———-将得到的数组命名为S1, S2;

同样对子数组S1进行拆分->[ ], [2], [ 5, 3] <——————–拆分之后,第一个子数组为空。将得到的数组命名为S12;

对子数组S2进行拆分—–>[ ], [8], [13, 10, 11]<—————将得到的数组命名为S22;

此时的数组S为———->2,5,3,6,8,13,10,11

对子数组S12进行拆分—->[3], [5],[ ];

对自数组S22进行拆分—->[10,11],[13],[]<——————–将得到的数组命名为S221

此时的数组S为———–>2,3,5,6,8,10,11,13

对子数组S221进行拆分—>[ ], [11], [13]

对后得到的数组为——–>2,3,5,6,8,10,11,13;

根据以上分析,编写快速排序算法程序,得到的程序如下:

复制代码

 #include <string> #include <iostream>  using namespace::std;  int Partition( int A[], int p, int q ) { int key = A[p]; int i = p; for(int j = p + 1 ;j < q; j++ ) { if( A[j] <= key ) { i++; swap<int>(A[i], A[j]); } } swap<int>(A[p], A[i]); return i; }  void QuickSort( int A[], int p, int q ) { if( p < q ) { int r = Partition(A, p, q); QuickSort(A,p,r-1); QuickSort(A,r+1,q);} }  int main() { int A[10] = {8,1,4,9,0,3,5,2,7,6}; QuickSort(A,0,9); for( int k = 0; k < 10; k++ ) cout << A[k] << " "; cout << endl; }

复制代码
计算结果如图:

看似结果很好,但是很遗憾,在实际中,我们却并不采用这样的程序。为什么呢?因为该程序还有几点需要进行改进:

当我们输入的数组S是已经排序好的一列数,那么这个程序的运行时间将是O(n^2),这个效率是插入排序的效率,所以是很低很低的。(可以利用递归树进行具体分析)
为了提高效率,可以使得i和j分别从左边和右边进行搜索,将值分别与v进行对比,当S[i]>v而S[j]