首页 > 代码库 > 算法导论-排序(二)快速排序、随机化快速排序

算法导论-排序(二)快速排序、随机化快速排序

目录                                                                                       

     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   <-   p4     for j  <- p+1  to q5         do if  A[j] <  x   //小于主元的数据放在左边6                   then i  <-  i+17                          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)
100.00545230.006735520.00481085

0.0189227

1000.1080840.1077630.3774920.232845
10001.714271.4721249.58642.67323
1000034.79519.22263542.7430.3318
100000232.691233.02352846350.414
10000003032.33273.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

算法导论-排序(二)快速排序、随机化快速排序