復習データ構造:並べ替えアルゴリズム(5)――快速並べ替えの各種バージョン



    前にはすでにファーストクラスの基本思想を熟知していました.その実現の方法もいろいろあります.いくつかの一般的な実現方法を羅列します.
アルゴリズム導論上の一方向スキャンは、最後の要素を主成分として選択します.
#include<iostream>
using namespace std; 

int partition(int data[], int low, int high)
{
	int pivot = data[high];  // let the last atom be the pivot 
	int i = low - 1;  // mark the pivot's true index: i+1
	for(int j = low; j < high; j++)  //     low ~ high,      high-1  
	{
		if(data[j] <= pivot)
		{
			i++;  //   pivot        
			swap(data[i], data[j]);  //        ,  pivot i+1,    data[j]  i   
		}
	}

	swap(data[i+1], data[j]);  //           i+1,    pivot,  data[j]
	
	return i+1;  // return the true index of pivot, that is, i+1
}

void quickSort(int data[], int low, int high)
{
	if(low < high)
	{
		int k = partition(data, low, high); 
		quickSort(data, low, k-1); 
		quickSort(data, k+1, high); 
	}
}


int main()
{
	int data[] = {2, 6, 3, 8, 1, 4}; 
	quickSort(data, 0, 5); 

	for(int i = 0; i < 6; i++)
		cout<<data[i]<<' '; 
	cout<<endl; 

	return 0; 
}
バージョン2:双方向スキャンで、最初の要素をメイン要素として選択します.
#include<iostream>
using namespace std; 

void print(int a[], int n){  
    for(int j= 0; j<n; j++){  
        cout<<a[j] <<"  ";  
    }  
    cout<<endl;  
}  
  
void swap(int *a, int *b)  
{  
    int tmp = *a;  
    *a = *b;  
    *b = tmp;  
}  

//        
int partition(int a[], int low, int high)  
{  
    int privotKey = a[low];                             //      
    while(low < high){                                   //               
        while(low < high  && a[high] >= privotKey) --high;  // high         ,   low+1   。               
        swap(&a[low], &a[high]);  
        while(low < high  && a[low] <= privotKey ) ++low;  
        swap(&a[low], &a[high]);  
    }  
    print(a,10);  
    return low;  
}  
  
  
void quickSort(int a[], int low, int high){  
    if(low < high){  
        int privotLoc = partition(a,  low,  high);  //        
        quickSort(a,  low,  privotLoc -1);          //            
        quickSort(a,   privotLoc + 1, high);        //            
    }  
}  
  
int main(){  
    int a[10] = {3,1,5,7,2,4,9,6,10,8};  
    cout<<"   :";  
    print(a,10);  
    quickSort(a,0,9);  
    cout<<"  :";  
    print(a,10);  
	return 0; 
}  
バージョン3:任意で1つの要素をメインとして選択します.
//                        ,              ,                     

#include<iostream>
using namespace std; 


//       ,       ,    “&” 
void swap(int& a , int& b)
{
 int temp = a;
 a = b;
 b = temp;
}

//    [lo,hi)      
int rand(int lo,int hi)
{
 int size = hi-lo+1;
 return  lo+ rand()%size; 
}

//  ,     ,    a           
int RandPartition(int* data, int lo , int hi)
{    
 //                                
 swap(data[rand(lo,hi)], data[lo]);
    int key = data[lo];
 int i = lo;
 
    for(int j=lo+1; j<=hi; j++)
 {
  if(data[j]<=key)
  {
   i = i+1;
   swap(data[i], data[j]);
  }            
 } 
 swap(data[i],data[lo]);
 return i;
}

//       
void RandQuickSortMid(int* data, int lo, int hi)
{
 if(lo<hi)
 {
  int k = RandPartition(data,lo,hi);
  RandQuickSortMid(data,lo,k-1);
  RandQuickSortMid(data,k+1,hi);
 }
}
int main()
{
 const int N = 100; //        “  ”  。           ,     N=10000。
 int *data = new int[N];      
    for(int i =0; i<N; i++)
  data[i] = rand();   //  ,      ,      。 
    for(i=0; i<N; i++)
  cout<<data[i]<<" ";
    RandQuickSortMid(data,0,N-1);
 cout<<endl;
 for(i=0; i<N; i++)
  cout<<data[i]<<" ";
 cout<<endl;
    return 0;
}
三数取中を主元とする.
    上記のプログラムバージョンは、アルゴリズム導論において一方向スキャンにおいて、最後の要素をハブ要素とし、Hoareバージョンとそのいくつかの変形において、最初の要素、または中間要素を中心として、最後に上述した高速秩序計算法のランダム化バージョンは、シーケンスのいずれかの要素を主成分としている.
    中枢要素の選択、すなわち、主要素の選択は、最終的な効率列を迅速に並べ替えることを決定しますか?
    答えは確かです.data[lo]、data[mid]、data[hi]の3つの要素のうち、2番目の大きさの要素を中心にしている場合、高速なソートアルゴリズムはO(N^2)の最悪の状況にならないように最大限に保証します.これはいわゆる三数取中分割の方法です.もちろん、そのパートナーシップの過程に対してです.
    
//         
int RandPartition(int* a, int p , int q)
{    
 //                ,    a[p], a[m], a[q]        
 int m=(p+q)/2;
 if(a[p]<a[m])
  swap(a[p],a[m]);
 if(a[q]<a[m])
  swap(a[q],a[m]);
 if(a[q]<a[p])
  swap(a[q],a[p]);
 int key = a[p];
 int i = p;
 
 for(int j = p+1; j <= q; j++)
 {
  if(a[j] <= key)
  {
   i = i+1;
   if(i != j) 
    swap(a[i], a[j]);                 
  }            
 } 
 
 swap(a[i],a[p]);  
 return i;
}

void QuickSort(int data[], int lo, int hi)
{
    if (lo<hi)
    {
        int k = RandPartition(data, lo, hi);
        QuickSort(data, lo, k-1);
        QuickSort(data, k+1, hi);
    }
}
バージョン5:再帰版ではない
 //        ?  ,     ,  ,      。
   if( (key-lo)<(key-hi) )
   {
    st.push(key+1);    
    st.push(hi);
    hi=key-1;
   }
   else
   {
    st.push(lo);
    st.push(key-1);
    lo=key+1;
   }   
  }
  if(st.empty()) 
   return;
  hi=st.top();
  st.pop();  
  lo=st.top();
  st.pop();  
 }while(1);
}
参考:
http://blog.csdn.net/hguisu/article/details/7776068
http://blog.csdn.net/xiazdong/article/details/8462393
http://blog.csdn.net/v_JULYv/articale/detail/6262915