Quicker Quick-Sort

Quicker Quick-Sort

关于快速排序

我们都知道快速排序有很好的O(nlogn),那么更快的快速排序在哪里呢?下面是我的学习记录。

--By JonsenElizee 2010/09/23

常规的快速排序

学习快速排序,最让人熟悉的是两个ptr左右来回指,一次排序后就把一个mid值放在了合适的位置上。这是我一个朋友的非递归的C++实现。我改写一点点,就是加了C的rand()来设置数组值,然后编译运行这个算法,你可能还不能随随便便的写出这个算法,但效果真的很不乐观,也不知道要运行多久才能排序完26*50的字符串。后面我们会看到一个很精悍的算法。。。

 1  #include  < stack >
 2  #include  < vector >
 3  #include  < iostream >
 4  #include  < stdlib.h >
 5  #include  < stdio.h >
 6  #include  < time.h >
 7 
 8  using   namespace  std;
 9 
10  typedef  struct  _record
11  {
12       int  begin;
13       int  end;
14  }record;
15 
16  void  quick_sort( int  a[], int  len)
17  {
18      vector < record >  do_job;
19      record temp;
20      temp.begin  =   0 ;
21      temp.end  =  len - 1 ;
22      do_job.push_back(temp);
23 
24       while  (do_job.size()   !=   0 ) {
25          record temp  =  do_job.back();
26          do_job.pop_back();
27      
28           int  low  =  temp.begin;
29           int  high  =  temp.end;
30           int  key  =  a[low];
31           while  (low  <  high) {
32               while (low  <  high  &&  a[high]  >=  key) high -- ;
33              a[low]  =  a[high];
34               while (low  <  high  &&  a[low]  <=  key) low ++ ;
35              a[high]  =  a[low];
36          }
37          a[low]  =  key;
38 
39          record temp1;
40          temp1.begin  =  temp.begin;
41          temp1.end  =  low - 1 ;
42           if  (temp1.begin  <  temp1.end) { do_job.push_back(temp1); }
43 
44          record temp2;
45          temp2.begin  =  low + 1 ;
46          temp2.end  =  temp.end;
47           if  (temp2.begin  <  temp2.end) { do_job.push_back(temp2); }
48      }
49  }
50  int  main()
51  {
52       int  a[ 26 * 50 ];
53       int  i  =   0 ;
54       while (i  <   26 * 50 ) a[i]  =  rand()  %   100 ;
55       int  count  = sizeof (a)  /   sizeof ( int );
56      quick_sort(a,count);
57       for  ( int  i  =   0 ; i  <  count; i ++ ) cout << a[i] << endl;
58       return   0 ;
59  }
60 


更简更快快速排序

这种快速排序不是最快的,特别是基本有序时会退化到O(n^2),理论上基于比较的排序不会小于O(nlogn),但还是有加速的可能。下面这个是《Programming Pearls 2nd》里面的方法,这个算法真的很精悍,运行完26*50的一个排序,只需要0.09秒,我的实现如下。

Quicker Quick-Sort_第1张图片

运行时是给的一个长度为26*50的一个字符数组,对它进行排序:

Quicker Quick-Sort_第2张图片


更简更快快速排序++

研究上面算法的执行过程,遵循大师的思路,我改写了算法,在我的X61+Redhat EL5上运行速度比上面的算法快了8倍,也就是运行完26*50长的排序,只需要0.01秒!最后我明白一个道理,要有思想,要有毅力,要有实践。完稿时,我发现这个算法还有改进的余地。特和大家分享。多多指点。

运行输入和quick.c中的一样:

Quicker Quick-Sort_第3张图片

运行结果对比

常规的那个非递归的算法从我写这个文件到现在,它还在运行着。。。

第二个和第三个时间对比如下图:

(加不加优化-O3都是一样的结果,在我的X61上,gcc version 4.1.2 20080704 (Red Hat 4.1.2-48))

Quicker Quick-Sort_第4张图片

改进的myquick.c的运行时间是quick.c的1/9。

最后,我不得不用Ctrl+C把那个常规的给KILL掉。

Real, User and Sys process time statistics

One of these things is not like the other. Real refers to actual elapsed time; User and Sys refer to CPU time used only by the process.
    *Real is wall clock time - time from start to finish of the call. This is all elapsed time including time slices used by other processes and time the process spends blocked (for example if it is waiting for I/O to complete).
    *User is the amount of CPU time spent in user-mode code (outside the kernel) within the process. This is only actual CPU time used in executing the process. Other processes and time the process spends blocked do not count towards this figure.
    *Sys is the amount of CPU time spent in the kernel within the process. This means executing CPU time spent in system calls within the kernel, as opposed to library code, which is still running in user-space. Like 'user', this is only CPU time used by the process.
      User+Sys will tell you how much actual CPU time your process used.

 

源代码

核心算法对比图

Quicker Quick-Sort_第5张图片

Quicker Quick-Sort_第6张图片

quick.c源代码

 1  #include  < stdio.h >
 2  #include  < string .h >
 3  #include  < stdlib.h >
 4  #include  < time.h >
 5 
 6  void  quick( char *  str,  int  low,  int  hig);
 7  void  swap( char *  a,  char *  b);
 8 
 9  int  main()
10  {
11       char  ary[]  = //26*50长的字符串数组,内容参考上图。
12       char *  str  =  ary;
13      printf( " calling quick " );
14      quick(str,  0 , strlen(str) - 1 );
15       return   0 ;
16  }
17 
18  void  quick( char *  str,  int  low,  int  hig) {
19       if (low  >=  hig)  return ;
20      srand(time(NULL));
21       //  get a random key
22       // swap(str + low, str + low + (rand() % (hig - low + 1)));
23       int  i  =  low, j  =  hig  +   1 , key  =  str[low];
24       while ( 1 )
25      {
26           while ( ++ <=  hig  &&  str[i]  <=  key);
27           while ( -- >=  low  &&  str[j]  >   key);
28           if (i  >  j)  break //  no need to do swap
29          swap(str  +  i, str  +  j);
30      }
31      swap(str  +  low, str  +  i  -   1 );  //  swap key to i-1 position
32      quick(str, low, i  -   2 );
33      quick(str, i, hig);
34  }
35 
36  void  swap( char *  a,  char *  b) {
37       if (a  ==  b)  return ;
38       * ^=   * b;  * ^=   * a;  * ^=   * b;
39  }
40 

 

 

myquick.c源代码

 1  #include  < stdio.h >
 2  #include  < string .h >
 3  #include  < stdlib.h >
 4  #include  < time.h >
 5 
 6  void  myquick( char *  str,  int  low,  int  hig);
 7  void  swap( char *  a,  char *  b);
 8 
 9  int  main()
10  {
11       char  ary[]  = //26*50长的字符串,同quick.c的输入。
12       char *  str  =  ary;
13      printf( " calling myquick " );
14      myquick(str,  0 , strlen(str) - 1 );
15       return   0 ;
16  }
17 
18  void  myquick( char *  str,  int  low,  int  hig) {
19       if (low  >=  hig)  return ; //  no need to sort elements
20       //  elements in the right of [m] are not sorted
21       int  m  =  low, i  =  low, j  =  hig, key  =  low;
22       //  skip any elements that <= [key]
23       while (i  <=  hig  &&  str[i]  <=  str[key]) {i ++ ; m ++ ;}
24       //  skip elements > [key]
25       while (j  >=  low  &&  str[j]  >  str[key]) j -- ;
26       //  initially, i==j is impossible
27       while (i  <=  j) {
28           //  swap small one to m-position
29           if (str[i]  <=  str[key]) { swap(str  +  m ++ , str  +  i); }
30          i ++ ;
31      }
32      swap(str  +  low, str  +  m - 1 );
33      myquick(str, low, m  -   2 );
34      myquick(str, m, hig);
35       return ;
36  }
37 
38  void  swap( char *  a,  char *  b) {
39       if (a  ==  b)  return ;
40       * ^=   * b;  * ^=   * a;  * ^=   * b;
41  }
42 




你可能感兴趣的:(Quicker Quick-Sort)