算法思想:
快速排序采用的思想是分治思想。
快速排序是找出一个元素(理论上可以随便找一个)作为基准(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 }
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 }