算法導論-排序(二)快速排序、隨機化快速排序

目錄                                                                 

     一、本文介紹

     二、快速排序

     三、隨機化快速排序

     四、完整源碼

     五、參考資料

內容                                                                

     一、本文介紹                                                                     

           主要內容分爲兩部分,一部分是介紹快速排序算法,分析其在最好、最壞以及最好最差交替出現狀況下的算法效率;另外一部分則是介紹隨機化快排算法,以及分析其算法複雜度。最後給出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)  //遞歸快排右子數組

   接下來分析快排的算法效率

    1)最壞狀況下分析

         當輸入序列是正序或者是反序的時候,效率最壞,這時效率是Θ(n2)編程

    2)  最優狀況下分析

       其餘狀況下的算法效率趨向於Θ(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
View Code

     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
View Code

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 }
View Code

   輸出:

 

排序算法時間比較:

數組大小 快速排序(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)能夠發現插入排序沒有優點、特別是數組比較大時耗時太多;2)快速排序、隨機化快速排序、歸併排序性能不錯,然而兩種快排比歸併排序性能好點;3)當數據量變大時,能夠看出性能排序爲快速排序、隨機化快速排序、歸併排序、插入排序;4)因爲這裏的數組是由隨機數產生的,沒有顯示出隨機化快速排序的優點,可是當數組爲已排序狀況下隨機化快排將比快排性能好。

     五、參考資料                                                                             

      【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

相關文章
相關標籤/搜索