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


目錄                                                                 

     1、本文介紹

     2、快速排序

     3、隨機化快速排序

     4、完整源碼

     5、參考資料

內容                                                                

     1、本文介紹                                                                     

           主要內容分為兩部分,一部分是介紹快速排序算法,分析其在最好、最壞以及最好最差交替出現情況下的算法效率;另一部分則是介紹隨機化快排算法,以及分析其算法復雜度。最后給出c++實現代碼。

     2、快速排序                                                                           

        快速排序也是基於分治思想,首先把要排序的數組分為兩份,然后再分別對分好的子數組進行快速排序。當子數組為1個元素時遞歸介紹,排序完成。快速排序屬於“原地排序”,就是說在原有的數組內存上排序、不占用其他內存。歸並排序就不一樣,它則需要額外的空間來進行歸並排序操作。下圖是快速排序的分治思想:

由上圖可以知道,快速排序里面最關鍵的就是第一步:分化(Partition)的步驟,這是該算法處理問題的核心。所以我們可以把快排看成是遞歸地划分數組,就像歸並排序是遞歸地合並數組一樣。關於Paritition的具體算法,目前有好幾種,其偽代碼稍有不同但是它們的原理都是一樣的。當然最重要的一點是分化(Partition)的算法復雜度都是線性的,也就是O(n)。下面是分化(Partition)的一種偽碼:

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)

  那么我們如何保證我們總是效率處於最優情況下的呢?這就是隨機化快速排序需要解決的問題。

     3、隨機化快速排序                                                                  

        我們已經知道,若輸入本身已被排序,那么對於快排來說就糟了。那么如何避免這樣的情況?一種方法時隨機排列序列中的元素;另一種方法時隨機地選擇主元(pivot)。這便是隨機化快速排序的思想,這種快排的好處是:其運行時間不依賴於輸入序列的順序。

      經分析, 隨機化快排的算法效率是Θ(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 }

     4、完整源碼                                                                            

       下面源碼包含之前討論過的插入排序、歸並排序算法。最后給出時間比較

      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)由於這里的數組是由隨機數產生的,沒有顯示出隨機化快速排序的優勢,但是當數組為已排序情況下隨機化快排將比快排性能好。

     5、參考資料                                                                             

      【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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM