经典算法回顾之快速排序【交换排序】

算法思想:

  快速排序采用的思想是分治思想。

  快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。

算法【算法导论】:

 1 QuickSort(A,start,end)
 2 
 3 if(start<end)
 4     then q<-Partition(A,start,end)
 5 QuickSort(A,start,q-1)
 6 QuickSort(A,q+1,end)
 7 
 8 
 9 //数组划分!!!
10 Partion(A,start,end)
11 
12 index<-random(start,end)
13 exchange A[end]<->A[index]
14 small<-start-1
15 for index<-start to end-1
16       do if A[index] < data[end]
17          then small<-small+1
18               if small!= index
19                 exchange A[index] <-> A[small]
20 exchange A[small+1]<->exchange A[end]
21 return small+1          

  快速排序复杂度:最坏O(N2);平均O(NlogN)

  快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。

  最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)

  在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)

  尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。

完整代码如下:

 1  1 #include <algorithm>
 2  2 #include <stdexcept>
 3  3 #include <iostream>
 4  4 using namespace std;
 5  5 
 6  6 // Random Partition
 7  7 int RandomInRange(int min, int max)
 8  8 {
 9  9     int random = rand() % (max - min + 1) + min;
10 10     return random;
11 11 }
12 12 
13 13 
14 14 int Partition(int data[], int length, int start, int end)
15 15 {
16 16     if(data == NULL || length <= 0 || start < 0 || end >= length)
17 17 //        throw new std::exception("Invalid Parameters");
18 18 //Linux下不接受有参数的exception
19 19         throw new logic_error("Invalid Parameters");
20 20     int index = RandomInRange(start, end);
21 21     swap(data[index], data[end]);
22 22 
23 23     int small = start - 1;
24 24     for(index = start; index < end; ++ index)
25 25     {
26 26         if(data[index] < data[end])
27 27         {
28 28             ++ small;
29 29             if(small != index)
30 30                 swap(data[index], data[small]);
31 31         }
32 32     }
33 33     ++ small;
34 34     swap(data[small], data[end]);
35 35     return small;
36 36 }
37 37 
38 38 void QuickSort(int unsorted[],int length,int start,int end)
39 39 {
40 40     if(start < end)
41 41     {
42 42           int q = Partition(unsorted,length,start,end);
43 43           QuickSort(unsorted,length,start,q-1);
44 44           QuickSort(unsorted,length,q+1,end);
45 45     }
46 46 }
47 47 
48 48 
49 49 int main()
50 50 {
51 51     int unsorted[] = {3,6,1,4,5,11,23};
52 52     int length = sizeof(unsorted)/sizeof(int);
53 53 
54 54     for(int i=0;i<length;++i)
55 55        cout<<unsorted[i]<<" ";
56 56     cout<<endl;
57 57 
58 58     QuickSort(unsorted,length,0,length-1);
59 59     for(int i=0;i<length;++i)
60 60         cout<<unsorted[i]<<" ";
61 61     cout<<endl;
62 62 
63 63     return 0;
64 64 }
View Code

Partition()函数的另一种实现方式:

 1 int Partion(int data[], int length, int start, int end)
 2 {//之前一直纠结的另一种Partition()实现方法,因为其用赋值替代了交换,所以更好。
 3     if(data == NULL || length <= 0 || start < 0 || end >= length)
 4         throw new logic_error("Invalid Parameters");
 5         
 6     int index = RandomInRange(start, end);
 7     swap(data[index],data[end]);
 8     int pleft = start;
 9     int pright = end;
10     int temp = data[end];//保存基数的副本
11     
12     while(pleft < pright)
13     {
14         //!!注意顺序,因为基准为end,所以先从左向右遍历!!
15         //从左向右遍历,直到遇到大于temp的值
16         while(pleft < pright && data[pleft] <= temp)
17             pleft++;
18         if(pleft < pright)
19             data[pright--] = data[pleft];
20         //从右向左遍历,直到遇到小于temp的值
21         while(pleft < pright && data[pright] >= temp)
22             pright--;
23         if(pleft < pright)
24             data[pleft++] = data[pright];    
25     }
26     
27     data[pleft] = temp;
28     return pleft;    
29 }
原文地址:https://www.cnblogs.com/dreamrun/p/4365791.html