快速排序的多種實現比較

快速排序是基於分治模式處理的:對一個典型子數組A[p...r]排序的分治過程爲三個步驟:1.分解:A[p..r]被劃分爲倆個(可能空)的子數組A[p ..q-1]和A[q+1 ..r],使得A[p...q-1] <= A[q] <= A[q+1...r]2.解決:通過遞歸調用快速排序,對子數組A[p ..q-1]和A[q+1 ..r]排序。3.合併。
其中分解的方法有多種,很容易引起混淆,下面逐一介紹。
1. Lomuto從左至右單向掃描版:參見編程珠璣
int partition1(int A[], int p, int r)
{
	t = A[p];		// 首元素爲樞紐
	int m = p;
	for(i = p+1; i<=r; i++)
        {     /*   invariant: A[p+1...m] < A[p] && A[m+1...i-1]>=A[p]  */
		if( A[i] < t)
			swap(A[++m], i)
         }
        swap(A[p],A[m]);      //這次交換不可少
	return m;              	
}
2. Lomuto從右至左單向掃描版:參見編程珠璣
int partition2(int A[], int p, int r)
{
	t = A[p]; 		// 首元素爲樞紐
	int m = r+1;
	for(i = r; i>=p; i--)
        {     /*   invariant: A[m...r] >= A[p] && A[m-1...i]<A[p]  */
		if( A[i] >= t)
			swap(A[--m], i)
         }
        // swap(A[p],A[m]); 	//這次交換已經包含在for循環內
	return m;              	
}
3. Lomuto從左至右單向掃描版:參見算法導論
int partition3(int A[], int p, int r)
{
	t = A[r]; 		// 尾元素爲樞紐
	int m = p-1;
	for(i = p; i<r; i++)
        {     
		if( A[i] <= t)
			swap(A[++m], i)
         }
        swap(A[r],A[m+1]); 	//這次交換不可少
	return m+1;              	
}

上述三個算法的缺點是:當A數組所有元素相同時,n-1次劃分中每次

劃分都需要O(n)時間去掉一個元素,時間複雜度O(n*n)。

4. Hoare雙向掃描版:參見博客<結構之法>

int partition4(int A[],int p,int r)  //雙向掃描  
{  
  int key=A[p];  // 首元素爲樞紐
  int i=p-1;  
  int j=r+1;  
  for(;;)  
  {  
     do{  
          j--;  
      }while(A[j]>key);  
  
     do{  
         i++;  
      }while(A[i]<key);  
  
     if(i<j)  
     {  
         swap(A[i],A[j]);  
     }  
     else  
     {   
        return j;  //注意這裏的返回值是j。
      }  
   }  
}  

5. Hoare變種:參見嚴蔚敏數據結構
int partition5(int A[],int p,int r)  //雙向掃描。
{
 int key=A[p];   //以第一個元素爲主元
 int i=p;
 int j=r;
 while(i<j)
 {
  	while(key<=A[h] && i<j) 
   		j--;
  	A[i]=A[j];
  	while(A[i]<=key && i<j) 
   		i++;
  	A[j]=A[i];
 }
 A[i]=key;  
 return i;    //注意這裏返回的是i
} 

6. STL qsort 算法:參見侯捷STL源碼剖析

int partition6(int A[],int p,int r,int key) //雙向掃描。
{
 //這裏的key可以是數組中任意一元素的值,但通常是首、尾、中間元素的中位數的值。
 //這裏的r其實是數組最後元素的下一個元素,符合STL左閉右開的假定
 while(true)
 {
  	while(A[p]<key)   ++p;
  	--r;
  	while(key<A[r])   --r;
        if( !(p<r) )  return p; //注意這裏返回的是p
	swap(A[p],A[r]);
	++r;
 }   
} 
其實我感覺小於號改成小於等於號也行,可能是STL出於泛化的考慮,數據有可能不支持小於等於號。
以上是在看書和看博客過程中的一些思考,可能有些錯誤,僅記下來待以後看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章