主要內容分爲兩部分,一部分是介紹快速排序算法,分析其在最好、最壞以及最好最差交替出現狀況下的算法效率;另外一部分則是介紹隨機化快排算法,以及分析其算法複雜度。最後給出c++實現代碼。html
快速排序也是基於分治思想,首先把要排序的數組分爲兩份,而後再分別對分好的子數組進行快速排序。當子數組爲1個元素時遞歸介紹,排序完成。快速排序屬於「原地排序」,就是說在原有的數組內存上排序、不佔用其餘內存。歸併排序就不同,它則須要額外的空間來進行歸併排序操做。下圖是快速排序的分治思想:
ios
由上圖能夠知道,快速排序裏面最關鍵的就是第一步:分化(Partition)的步驟,這是該算法處理問題的核心。因此咱們能夠把快排當作是遞歸地劃分數組,就像歸併排序是遞歸地合併數組同樣。關於Paritition的具體算法,目前有好幾種,其僞代碼稍有不一樣可是它們的原理都是同樣的。固然最重要的一點是分化(Partition)的算法複雜度都是線性的,也就是O(n)。下面是分化(Partition)的一種僞碼:c++
1 Partition(A,p,q) 2 x <- A[p] //選第一個爲主元 3 i <- p 4 for j <- p+1 to q 5 do if A[j] < x //小於主元的數據放在左邊 6 then i <- i+1 7 exch A[i] <-> A[j] // 交換A[i] A[j] 8 exch A[p] <-> A[i] // 交換 9 return i //返回劃分好後主元索引
分劃好後就是簡單的遞歸,下面是快排的僞代碼:算法
1 QuickSort(A,p,q) 2 if p < q //不知足就介紹遞歸 3 then r <- Partition(A,p,q) //分劃 4 QuickSort(A,p , r-1) //遞歸快排左子數組 5 QuickSort(A , r+1 ,q) //遞歸快排右子數組
當輸入序列是正序或者是反序的時候,效率最壞,這時效率是Θ(n2)編程
其餘狀況下的算法效率趨向於Θ(nlgn)數組
那麼咱們如何保證咱們老是效率處於最優狀況下的呢?這就是隨機化快速排序須要解決的問題。dom
咱們已經知道,若輸入自己已被排序,那麼對於快排來講就糟了。那麼如何避免這樣的狀況?一種方法時隨機排列序列中的元素;另外一種方法時隨機地選擇主元(pivot)。這即是隨機化快速排序的思想,這種快排的好處是:其運行時間不依賴於輸入序列的順序。ide
經分析, 隨機化快排的算法效率是Θ(nlgn)。性能
實現:咱們只需在選取主元時加入隨機因素便可。其餘與快排同樣測試
下面是分化(Partition)編程(c++)實現
1 int Random_Partition(vector<T> &A,int p,int q) 2 { 3 int i=rand()%(q-p)+p; //此行與快排不一樣、加入隨機數參數器 4 Swap(A[i],A[p]); //此行與快排不一樣、隨機選取主元 5 return Partition(A,p,q);//這次與快速排序同樣 6 }
// 隨機化快速排序
1 void Random_Quick_Sort(vector<T> &A,int p,int q) 2 { 3 if (p<q) 4 { 5 int i=Random_Partition(A,p,q); 6 Random_Quick_Sort(A,p,i-1); 7 Random_Quick_Sort(A,i+1,q); 8 } 9 }
下面源碼包含以前討論過的插入排序、歸併排序算法。最後給出時間比較
CTimer.h (測試間的頭文件實現,不懂無需糾結)
1 #ifndef CTIMER_HH 2 #define CTIMER_HH 3 class CTimer 4 { 5 public: 6 CTimer() 7 { 8 QueryPerformanceFrequency(&m_Frequency); 9 Start(); 10 } 11 void Start() 12 { 13 QueryPerformanceCounter(&m_StartCount); 14 } 15 double End() 16 { 17 LARGE_INTEGER CurrentCount; 18 QueryPerformanceCounter(&CurrentCount); 19 return double(CurrentCount.LowPart - m_StartCount.LowPart) *1000/ (double)m_Frequency.LowPart; 20 } 21 void ShowNow() 22 { 23 LARGE_INTEGER CurrentCount; 24 QueryPerformanceCounter(&CurrentCount); 25 cout<<"Timer Count is:"<<double(CurrentCount.LowPart - m_StartCount.LowPart)*1000 / (double)m_Frequency.LowPart<<endl; 26 } 27 private: 28 LARGE_INTEGER m_Frequency; 29 LARGE_INTEGER m_StartCount; 30 }; 31 #endif
Sort.h (排序算法[插入排序、歸併排序、快速排序、隨機化快速排序]實現頭文件)
1 #ifndef SORT_HH 2 #define SORT_HH 3 template<typename T >//帶模板 4 class Sort 5 { 6 public: 7 void insertion_sort(vector<T> &A);//插入排序 8 void merge_sort(vector<T> &A,int p,int r);//歸併排序 9 void print_element(vector<T> A);//打印數組 10 void Quick_Sort(vector<T> &A,int p,int q);//快速排序 11 int Partition(vector<T> &A,int p,int q);//分劃 12 void Swap(T &m,T &n);//交換數據 13 void Random_Quick_Sort(vector<T> &A,int p,int q);//隨機化快速排序 14 int Random_Partition(vector<T> &A,int p,int q);//隨機化分劃 15 private: 16 void merge(vector<T> &A,int p,int q,int r);// 歸併排序子程序 17 }; 18 template<typename T>//插入排序 19 void Sort<T>::insertion_sort(vector<T> &A) 20 { 21 int i,j; 22 T key; 23 int len=A.size(); 24 for (j=1;j<len;j++) 25 { 26 i=j-1; 27 key=A[j]; 28 while (i>=0&&A[i]>key) 29 { 30 A[i+1]=A[i]; 31 i--; 32 } 33 A[i+1]=key; 34 } 35 } 36 37 template<typename T>// 歸併排序子程序 38 void Sort<T>::merge(vector<T> &A,int p,int q,int r) 39 { 40 int n1=q-p+1; 41 int n2=r-q; 42 T *L=new T[n1+1]; 43 T *R=new T[n2+1]; 44 45 for (int i=0;i<n1;i++) 46 L[i]=A[i+p]; 47 for (int i=0;i<n2;i++) 48 R[i]=A[i+q+1]; 49 50 L[n1]=R[n2]=INT_MAX; 51 52 int i=0,j=0; 53 for (int k=p;k<=r;k++) 54 { 55 if (L[i]>R[j]) 56 { 57 A[k]=R[j]; 58 j++; 59 } 60 else 61 { 62 A[k]=L[i]; 63 i++; 64 } 65 } 66 67 delete[] L; 68 delete[] R; 69 70 } 71 72 template<typename T>//歸併排序 73 void Sort<T>::merge_sort(vector<T> &A,int p,int r) 74 { 75 if (p<r) 76 { 77 int mid=(p+r)/2; 78 merge_sort(A,p,mid); 79 merge_sort(A,mid+1,r); 80 merge(A,p,mid,r); 81 } 82 } 83 84 template<typename T>//交換數據 85 void Sort<T>::Swap(T &m,T &n) 86 { 87 T tmp; 88 tmp=m; 89 m=n; 90 n=tmp; 91 } 92 93 /***********快速排序分劃程序*************/ 94 template<typename T> 95 int Sort<T>::Partition(vector<T> &A,int p,int q) 96 { 97 T x=A[p]; 98 int i=p; 99 for (int j=p+1;j<=q;j++) 100 { 101 if (A[j]<x) 102 { 103 i=i+1; 104 Swap(A[i],A[j]); 105 } 106 } 107 Swap(A[p],A[i]); 108 return i; 109 } 110 template<typename T>//快速排序 111 void Sort<T>::Quick_Sort(vector<T> &A,int p,int q) 112 { 113 if(p<q) 114 { 115 int i=Partition(A,p,q); 116 Quick_Sort(A,p,i-1); 117 Quick_Sort(A,i+1,q); 118 } 119 } 120 121 template<typename T>//隨機化快速排序分劃程序 122 int Sort<T>::Random_Partition(vector<T> &A,int p,int q) 123 { 124 int i=rand()%(q-p)+p; 125 Swap(A[i],A[p]); 126 return Partition(A,p,q); 127 } 128 129 template<typename T>//隨機化快速排序 130 void Sort<T>::Random_Quick_Sort(vector<T> &A,int p,int q) 131 { 132 if (p<q) 133 { 134 int i=Random_Partition(A,p,q); 135 Random_Quick_Sort(A,p,i-1); 136 Random_Quick_Sort(A,i+1,q); 137 } 138 } 139 140 template<typename T>//打印數組 141 void Sort<T>::print_element(vector<T> A) 142 { 143 int len=A.size(); 144 for (int i=0;i<len;i++) 145 { 146 std::cout<<A[i]<<" "; 147 } 148 std::cout<<std::endl; 149 } 150 #endif
Sort_main.cpp (測試主程序)
1 #include <iostream> 2 #include <vector> 3 #include <time.h> 4 #include <Windows.h> 5 using namespace std; 6 #include "Sort.h" 7 #include "CTimer.h" 8 9 #define N 10 //排序數組大小 10 // 隨機參數排序數組 11 void Random(vector<int> &a,int n) 12 { 13 int i=0; 14 srand( (unsigned)time( NULL ) ); 15 while(i<n) 16 { 17 a[i++]=rand(); 18 } 19 } 20 int main() 21 { 22 Sort<int> sort1; 23 CTimer t; 24 vector<int > vec_int(N); 25 Random(vec_int,N); 26 cout<<"源數組:"; 27 sort1.print_element(vec_int); 28 t.Start(); 29 sort1.Quick_Sort(vec_int,0,vec_int.size()-1); 30 cout<<"快速排序:"<<t.End()<<"ms"<<endl; 31 sort1.print_element(vec_int); 32 Random(vec_int,N); 33 t.Start(); 34 sort1.Random_Quick_Sort(vec_int,0,vec_int.size()-1); 35 cout<<"隨機化快速排序:"<<t.End()<<"ms"<<endl; 36 sort1.print_element(vec_int); 37 Random(vec_int,N); 38 t.Start(); 39 sort1.insertion_sort(vec_int); 40 cout<<"插入排序:"<<t.End()<<"ms"<<endl; 41 sort1.print_element(vec_int); 42 Random(vec_int,N); 43 t.Start(); 44 sort1.merge_sort(vec_int,0,vec_int.size()-1); 45 cout<<"歸併排序:"<<t.End()<<"ms"<<endl; 46 sort1.print_element(vec_int); 47 48 system("PAUSE"); 49 return 0; 50 }
排序算法時間比較:
數組大小 | 快速排序(ms) | 隨機化快速排序(ms) | 插入排序(ms) | 歸併排序(ms) |
10 | 0.0054523 | 0.00673552 | 0.00481085 | 0.0189227 |
100 | 0.108084 | 0.107763 | 0.377492 | 0.232845 |
1000 | 1.71427 | 1.47212 | 49.5864 | 2.67323 |
10000 | 34.795 | 19.2226 | 3542.74 | 30.3318 |
100000 | 232.691 | 233.02 | 352846 | 350.414 |
1000000 | 3032.3 | 3273.46 | ......(太大、沒測) | 4017.02 |
【1】http://blog.csdn.net/xyd0512/article/details/8259382
【2】http://blog.csdn.net/kenden23/article/details/14558231
【3】http://www.cnblogs.com/lidabo/archive/2013/01/08/2850418.html