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

目录                                                                 

     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

posted @ 2014-09-13 17:50  平凡的幸福...  阅读(12881)  评论(0编辑  收藏  举报