快速排序算法學習筆記

快速排序是一種比較實用的排序算法,平均時間複雜度爲O(nlogn),最壞狀況爲O(n*n),最好狀況也是O(nlogn)。該算法基於分治處理思想,在數列中選取一個主元,根據這個主元把整個數列分爲兩部分:一部分比這個主元小,一部分比這個主元大。而後對這兩部分分別再選取主元劃分,以此遞歸下去。算法

針對一個A[p....r]的數組,其執行步驟能夠描述爲:數組

一、分組:A[p..r]被劃分爲兩個可能爲空的子數組A[p..q-1]和A[q+1..r],使得A[p..q-1] <= A[q] <= A[q+1..r];ui

二、解決:經過遞歸調用快速排序,對子數組A[p..q-1]和A[q+1..r]排序。spa

三、合併。.net

快速排序的關鍵是實現分組(partion),此過程有多種實現方法。主元能夠分別選取首、尾,或者使用三數取中法。數組掃描方向又能夠單向掃描和雙向掃描。另外,藉助棧結構,還有非遞歸版本的實現。code

目前,本身分析實現了的版本以下:blog

一、尾數做爲主元,從前日後單向掃描排序

貌似此版本是《算法導論》裏的實現版本,具體我也沒看過,好多博客裏都這樣說。僞代碼以下:遞歸

QUICKSORT(A, p, r)
 if p < r
    then q ← PARTITION(A, p, r)  
         QUICKSORT(A, p, q - 1)
         QUICKSORT(A, q + 1, r)
關鍵的分組過程:

PARTITION(A, p, r)
  x ← A[r]
  i ← p - 1
  for j ← p to r - 1
       do if A[j] ≤ x
             then i ← i + 1
                  exchange A[i] <-> A[j]
  exchange A[i + 1] <-> A[r]
  return i + 1
具體實現:

 int partionLast(int arr[], int p, int r){
     int x = arr[r];
     int i = p - 1;
      int j, tmp;
      for(j = p; j < r ; j++){
          if(arr[j] <= x){
              i++;
              tmp = arr[i];
              arr[i] = arr[j];
              arr[j] = tmp;
          }
      }   
      tmp = arr[i+1];
      arr[i+1] = arr[j];
      arr[j] = tmp;
      return i+1;
 }
<pre name="code" class="cpp">  void quicksort(int arr[], int p, int r){
      if(p<r){
          int q = partionLast(arr,p,r);
          quicksort(arr,p,q-1);
          quicksort(arr,q+1,r);
      }    
 }

 二、第一個數做爲主元,從前日後單向掃描 
  int partionFirst(int arr[], int p, int r){
       int x = arr[p];
       int i = p;
       int j,tmp;
       for(j = p+1; j <= r; j++){
           if(arr[j] <= x){
               i++;
              tmp = arr[i];
              arr[i] = arr[j];
              arr[j] = tmp;
          }                                                                                                         
      }    
      tmp = arr[i];
      arr[i] = arr[p];
      arr[p] = tmp;
      return i;
 }  
三、尾數做主元,雙向掃描

 int partionDoubleEnded(int arr[], int p, int r){
     int x = arr[r];
     int i = p;
     int j = r - 1;
     int tmp;
     do{  
         if(arr[i] <= x){
             i++;
         }else{
             if(arr[j] >= x){
                 j--;
             }else{
                 tmp = arr[i];
                 arr[i] = arr[j];
                 arr[j] = tmp;
                 i++;
             }
         }
     }while(i <= j&&j >= p);
     tmp = arr[i];
     arr[i] = arr[r];
     arr[r] = tmp;
     return i;
 } 

還有一種非遞歸的實現,網上搜了許多,彷佛只有一種實現方式,摘抄以下:

template<typename Comparable>
void quicksort2(vector<Comparable> &vec,int low,int high){
    stack<int> st;
    if(low<high){
        int mid=partition(vec,low,high);
        if(low<mid-1){
            st.push(low);
            st.push(mid-1);
        }
        if(mid+1<high){
            st.push(mid+1);
            st.push(high);
        }
        //其實就是用棧保存每個待排序子串的首尾元素下標,下一次while循環時取出這個範圍,對這段子序列進行partition操做
        while(!st.empty()){
            int q=st.top();
            st.pop();
            int p=st.top();
            st.pop();
            mid=partition(vec,p,q);
            if(p<mid-1){
                st.push(p);
                st.push(mid-1);
            }
            if(mid+1<q){
                st.push(mid+1);
                st.push(q);
            }       
 }


最後,附上三篇分析快速排序很是棒的文章:

http://blog.csdn.net/v_july_v/article/details/6116297ip

http://blog.csdn.net/v_JULY_v/article/details/6211155

http://blog.csdn.net/v_JULY_v/article/details/6262915

相關文章
相關標籤/搜索