快速排序【記錄一下代碼】


本文僅用作學習記錄,大神勿噴O(∩_∩)O~

代碼一、百度百科C++語言版本代碼,參考數據結構p274(清華大學出版社,嚴蔚敏)

 1 void Qsort1(int a[], int low, int high)//百度百科C++語言版本代碼 
 2 {/*參考數據結構p274(清華大學出版社,嚴蔚敏)*/
 3     if(low >= high) return;
 4     int first = low;
 5     int last = high;
 6     int key = a[first];/*用字表的第一個記錄作為樞軸*/
 7  
 8     while(first < last)
 9     {
10         while(first < last && a[last] >= key)
11         {
12             --last;
13         }
14         a[first] = a[last];/*將比第一個小的移到低端*/
15         while(first < last && a[first] <= key)
16         {
17             ++first;
18         }
19         a[last] = a[first];    
20         /*將比第一個大的移到高端*/
21     }
22     a[first] = key;/*樞軸記錄到位*/
23     Qsort1(a, low, first-1);
24     Qsort1(a, first+1, high);
25 }
View Code

代碼二、百度百科C語言版本代碼

 1 void Qsort2(int *a, int left, int right)//百度百科C語言版本代碼 
 2 {
 3     if(left >= right)/*如果左邊索引大於或者等於右邊的索引就代表已經整理完成一個組了*/
 4     {
 5         return ;
 6     }
 7     int i = left;
 8     int j = right;
 9     int key = a[left];
10      
11     while(i < j)                               /*控制在當組內尋找一遍*/
12     {
13         while(i < j && key <= a[j])/*而尋找結束的條件就是,1,找到一個小於或者大於key的數(大於或小於取決於你想升序還是降序)2,沒有符合條件1的,並且i與j的大小沒有反轉*/ 
14         {
15             j--;/*向前尋找*/
16         }
17         a[i] = a[j];/*找到一個這樣的數后就把它賦給前面的被拿走的i的值(如果第一次循環且key是a[left],那么就是給key)*/
18          
19         while(i < j && key >= a[i])/*這是i在當組內向前尋找,同上,不過注意與key的大小關系停止循環和上面相反,因為排序思想是把數往兩邊扔,所以左右兩邊的數大小與key的關系相反*/
20         {
21             i++;
22         }
23         a[j] = a[i];
24     }
25      
26     a[i] = key;/*當在當組內找完一遍以后就把中間數key回歸*/
27     Qsort2(a, left, i - 1);/*最后用同樣的方式對分出來的左邊的小組進行同上的做法*/
28     Qsort2(a, i + 1, right);/*用同樣的方式對分出來的右邊的小組進行同上的做法*/
29                        /*當然最后可能會出現很多分左右,直到每一組的i = j 為止*/
30 }
View Code

代碼三、坐在馬桶上看算法:快速排序。   鏈接:http://developer.51cto.com/art/201403/430986.htm

(來源頁面評論代碼有誤,測試沒發現問題。)

 1 void Qsort3(int a[],int left,int right) //坐在馬桶上看算法:快速排序。http://developer.51cto.com/art/201403/430986.htm 
 2 { 
 3     int i,j,t,temp; 
 4     if(left>right) return; 
 5                                 
 6     temp=a[left]; //temp中存的就是基准數 
 7     i=left; 
 8     j=right; 
 9     while(i!=j) 
10     { 
11         //順序很重要,要先從右邊開始找 
12         while(i<j && a[j]>=temp) 
13             j--; 
14         //再找右邊的 
15         while(i<j && a[i]<=temp) 
16             i++; 
17         //交換兩個數在數組中的位置 
18         if(i<j) 
19         { 
20             t=a[i]; a[i]=a[j]; a[j]=t; 
21         } 
22     } 
23     //最終將基准數歸位 
24     a[left]=a[i]; 
25     a[i]=temp; 
26                              
27     Qsort3(a,left,i-1);//繼續處理左邊的,這里是一個遞歸的過程 
28     Qsort3(a,i+1,right);//繼續處理右邊的 ,這里是一個遞歸的過程 
29 }
View Code

代碼四、白話經典算法系列之六 快速排序   鏈接: http://blog.csdn.net/morewindows/article/details/6684558#

鏈接頁面評論一致認為作者講解非常棒。

 1 void Qsort4(int s[], int l, int r)//白話經典算法系列之六 快速排序 http://blog.csdn.net/morewindows/article/details/6684558#
 2 {  
 3     if (l < r)  
 4     { 
 5         int i = l, j = r, x = s[l];
 6         while (i < j)
 7         {
 8             while(i < j && s[j] >= x) // 從右向左找第一個小於x的數  
 9                 j--;    
10             if(i < j)   
11                 s[i++] = s[j];  
12               
13             while(i < j && s[i] < x) // 從左向右找第一個大於等於x的數  
14                 i++;    
15             if(i < j)   
16                 s[j--] = s[i];  
17         }
18         s[i] = x;  
19         Qsort4(s, l, i - 1); // 遞歸調用   
20         Qsort4(s, i + 1, r);  
21     }
22 }  
View Code

代碼五、博客園~大器晚成~的代碼  鏈接:http://www.cnblogs.com/luchen927/archive/2012/02/29/2368070.html

原文代碼有誤,評論里面已經有園友指出。這里摘抄時已經修改,否則當待排序列有相等值則可能會死循環 。

 1 void Qsort5(int *v, int left, int right)//博客園“大器晚成”的代碼http://www.cnblogs.com/luchen927/archive/2012/02/29/2368070.html 
 2 {//原文代碼有錯誤,已經修改,否則當待排序列有相等值則會死循環 。修改以后,本代碼與百度百科代碼是相同 
 3     if(left < right)
 4     {
 5         int key = v[left];
 6         int low = left;
 7         int high = right;
 8         while(low < high)
 9         {
10             while(low < high && v[high] >= key)//原文 while(low < high && v[high] > key)
11             {
12                 high--;
13             }
14             v[low] = v[high];
15             while(low < high && v[low] <= key)//原文while(low < high && v[low] < key)
16             {
17                 low++;
18             }
19             v[high] = v[low];
20         }
21         v[low] = key;
22         Qsort5(v,left,low-1);
23         Qsort5(v,low+1,right);
24     }
25 }
View Code

代碼六、《C++一本通》page191快速排序代碼(請閱讀這一段代碼)

 1 void Qsort6(int *a,int l,int r)//《C++一本通》page191快速排序代碼 
 2 {  
 3     int i,j,mid,p;
 4     i=l;
 5     j=r; 
 6     mid=a[(l+r) / 2]; //將當前序列在中間位置的數定義為分隔數
 7     do
 8     {
 9         while (a[i]<mid) i++;//在左半部分尋找比中間數大的數
10         while (a[j]>mid) j--;//在右半部分尋找比中間數小的數
11         if (i<=j) 
12         { //若找到一組與排序目標不一致的數對則交換它們
13             p=a[i];a[i]=a[j];a[j]=p;
14             i++;j--; //繼續找
15         }
16     }while(i<=j);//注意這里不能少等號
17     if (l<j)  Qsort6(a,l,j);//若未到兩個數的邊界,則遞歸搜索左右區間
18     if (i<r)  Qsort6(a,i,r);
19 }
View Code

代碼七、來自北大郭煒老師在網易雲課堂開設的算法課程

 1 #include <iostream>
 2 using namespace std;
 3 void swap(int & a,int & b) //交換變量a,b值
 4 {
 5     int tmp = a;
 6     a = b;
 7     b = tmp;
 8 }
 9 void QuickSort(int a[],int s,int e)
10 {
11     if( s >= e) return;
12     int k = a[s];
13     int i = s,j = e;
14     while( i != j ) 
15     {
16         while( j > i && a[j] >= k ) --j;
17         swap(a[i],a[j]);
18         while( i < j && a[i] <= k ) ++i;
19         swap(a[i],a[j]);
20     } //處理完后, a[i] = k
21     QuickSort(a,s,i-1);
22     QuickSort(a,i+1,e);
23 }
24 int a[] = { 93,27,30,2,8,12,2,8,30,89};
25 int main()
26 {
27     int size = sizeof(a)/sizeof(int);
28     QuickSort(a,0,size-1);
29     for(int i = 0;i < size; ++i)
30         cout << a[i] << ",";
31     cout << endl;
32     return 0;
33 }
View Code

 

 

注意:在快排過程中划分區間時,必須要有等號,比如:

1     int i=left,j=right,key=a[left];
2     while(i<j)
3     {
4         while(i<j&&key>=a[j]) j--;//必須取等號,否則當數組兩頭的數相等時會死循環 
5         a[i]=a[j];
6         while(i<j&&key<=a[i]) i++;//必須取等號,否則當數組兩頭的數相等時會死循環
7         a[j]=a[i];
8     }

這種地方>=不能改為>,否則可能死循環。

 

 

 

測試用的主函數

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<time.h>
 4 
 5 int cmp(const void *a,const void *b)
 6 {    return *(int*)a - *(int*)b;   }
 7 int main()
 8 {
 9     int a[50],b[50],c[50],d[50],e[50],f[50],g[50],h[50];
10     int n,i,k=100000,index=1,count=0;
11     srand((unsigned)time(0));
12     
13     freopen("res.out","w",stdout);
14     for(;k>0;k--)
15     {
16         n=(rand()%2==1?49:50);
17          for(i=0;i<n;i++)
18          {
19              a[i]=rand()%3000;
20              h[i]=g[i]=f[i]=e[i]=d[i]=c[i]=b[i]=a[i];
21         }
22         
23         Qsort1(a, 0, n - 1);
24         Qsort2(b, 0, n - 1);
25          qsort(c,n,sizeof(c[0]),cmp);
26          Qsort3(e,0,n-1);
27          Qsort4(f,0,n-1);
28          Qsort5(g,0,n-1);
29          Qsort6(h,0,n-1);
30          
31         for(i= 0; i < n; i++)
32         {
33             if(a[i]!=c[i]||b[i]!=c[i]||e[i]!=c[i]||f[i]!=c[i]||g[i]!=c[i]||h[i]!=c[i]) 
34                 break;
35         }
36         if(i<n)
37         {
38             printf("case %d:\n",index);
39             printf("A:");//Qsort1的結果 
40             for(i=0;i<n;i++)
41                 printf("%d ",a[i]);
42                printf("\n");
43                
44                printf("B:");//Qsort2的結果 
45             for(i=0;i<n;i++)
46                 printf("%d ",b[i]);
47                printf("\n");
48                
49                printf("C:");//標准結果序列 
50             for(i=0;i<n;i++)
51                 printf("%d ",c[i]);
52                printf("\n");
53                
54                printf("E:");//Qsort3的結果 
55             for(i=0;i<n;i++)
56                 printf("%d ",e[i]);
57                printf("\n");
58                
59                printf("F:");//Qsort4的結果 
60             for(i=0;i<n;i++)
61                 printf("%d ",f[i]);
62                printf("\n");
63                
64                printf("G:");//Qsort5的結果 
65             for(i=0;i<n;i++)
66                 printf("%d ",g[i]);
67                printf("\n");
68                
69                printf("H:");//Qsort6的結果 
70             for(i=0;i<n;i++)
71                 printf("%d ",h[i]);
72                printf("\n");
73                
74                printf("D:");//原未排序序列 
75             for(i=0;i<n;i++)
76                 printf("%d ",d[i]);
77                printf("\n");
78         }
79         else { printf("case %d is ok!\n",index); count++;}
80         index++;
81     }
82     printf("%d of %d is ok!\n",count,index-1);
83     return 0;
84 }
View Code

 

其實 Qsort1、Qsort2、Qsort5(博客園代碼修改以后)三份代碼是一樣的
Qsort4跟上面幾個是差不多的,但稍有一點點改變
Qsort3思路變化比較大一些。
Qsort6簡直就是另類代碼風格,瞎搞的,不過也是對的。
學習記住 Qsort1、Qsort2、Qsort5之一或者Qsort4即可。

經過在洛谷OJ  P1177 測試,代碼六應該是最合理的,大家還是記住代碼六吧。。。。。。

(利用庫函數qsort在洛谷OJ  P1177提交確實也是AC的,然后利用代碼六去提交也可以過。說明OJ的數據沒問題。)

其余代碼的分割點元素的選擇都是選第一個元素,這個決策是一個不合理的決策,會導致算法的時間復雜度在某些情況下變為N^2級別的。雖然代碼六不能夠完全避免這個情況,但是相對而言比較合理一些。具體論述請參考《數據結構與算法分析:C語言描述(原書第2版)》對快速排序的描述。

 


免責聲明!

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



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