常見算法排序,冒泡排序,快排,堆排,歸併排序

排序


  1. 插入類排序
1 、直接插入排序          O(n2)      O(n)              O(n2)

每次將一個待排序元素按照關鍵字大小插入到已經排序的序列中去。

void insert(int a[],int n)
{
     int i,j;
     int temp;
     for(i=1;i<=n;i++)    //從第二個元素開始,由於第一個元素確定是有序的
     {
          temp=a[i];     //temp存儲a[i]防丟失
          j=i-1;
          while(j>=0 && temp<a[j])    //在i以前的元素已是有序的
          {
               a[j+1] = a[j];
               j--;     //一個個日後移
          }
          a[j+1]=temp;
     }
}


  1. 折半插入排序         O(n2)      O(n)              O(n2)

折半查找法尋找元素插入位置。與 1 最大不一樣在於, 1 用的是順序查找法。

  1. 希爾排序
    縮小增量排序。實質就是分組插入排序。 把記錄按步長分組,對每組記錄採用直接插入排序方法進行排序。 隨着步長逐漸減少,所分紅的組包含的記錄愈來愈多,當步長的值減少到 1 時,完成排序。 一個好的增量序列有如下特徵:最後一個增量必須爲1;儘可能避免序列中的值,尤爲是相鄰的值,互爲倍數。

  1. 交換類排序

1 、冒泡排序          O(n2)      O(n)              O(n2)

          結束條件是一趟排序中未發生元素交換。

   基本原理:依次比較兩個相鄰的數, 如果按從大到小排序,將大數放前,小數放後,直到比較到最後兩位數。重複上述步驟,直到一趟排序中未發生元素交換爲止。

// 普通冒泡
void bubble_sort(int a[],int n)//n爲數組a的元素個數
{
  //必定進行N-1輪比較
  for(int i=0; i<n-1; i++)
  {
       //每一輪比較前n-1-i個,即已排序好的最後i個不用比較
       for(int j=0; j<n-1-i; j++)
       {
             if(a[j] > a[j+1])
            {
                 int temp = a[j];
                 a[j] = a[j+1];
                 a[j+1]=temp;
            }
       }
  }
}

// 優化實現
void bubble_sort_better(int a[],int n)//n爲數組a的元素個數
{
  //最多進行N-1輪比較
  for(int i=0; i<n-1; i++)
  {
      bool isSorted = true;
      //每一輪比較前n-1-i個,即已排序好的最後i個不用比較
      for(int j=0; j<n-1-i; j++)
     {
        if(a[j] > a[j+1])
        {
           isSorted = false;
           int temp = a[j];
           a[j] = a[j+1];
           a[j+1]=temp;
        }
     }
     if(isSorted) break; //若是沒有發生交換,說明數組已經排序好了
  }
}

2 、快速排序          O(nlog2n)       O(nlog2n)       O(n2)

       分治的思想。分治法一般有3步:Divide(分解子問題的步驟)Conquer(遞歸解決子問題的步驟)、Combine(子問題解求出來後合併成原問題解的步驟)。而求解遞歸式的三種方法有:算法

(1)替換法:主要用於驗證遞歸式的複雜度。數組

(2)遞歸樹:可以大體估算遞歸式的複雜度,估算完後能夠用替換法驗證。ide

(3)主定理:用於解一些常見的遞歸式。優化

快排中,基準的左邊全是比它小的,右邊都是大的。三種取基準的方法:第一個或最後一個元素,中間元素,隨機元素。

待排序列越接近有序算法效率越。當每次劃分時,若都能分紅兩個等長的子序列時,效率會達到最大。最理想的方法是,選擇的基準剛好能把待排序序列分紅兩個等長的子序列

遞歸進行的,遞歸須要的輔助,所以輔助空間爲 O(log2n)

void quiksort(int a[],int start,int end)
{
  int low = start;
  int high= end;
  int key = a[low];

  if( start < end)
  {
       while(low <high && key<=a[high])
       high--; //若是high所在的值不比key小,就往左移動
       a[low] = a[high]; //遇到比key小的high值,就把a[high]值給a[low],a[low]本來的值已經在key裏面了
       while(low < high && a[low] <= key)
            low++;
       a[high]= a[low];
       a[low]=key; //此時的low的左邊全是比key小的,右邊全是比key大的,把key值放大當前low位置
       quiksort(a,start,low-1);//左邊重複
       quiksort(a,low+1,end);//右邊重複
  }
  else
       return;
}


  1. 選擇類排序

  1. 簡單選擇排序         

從頭到尾順序掃描未排序序列,選最小的元素與第一個進行交換。

  1. 堆排序      O(nlog2n)       O(nlog2n)       O(nlog2n)

從無序序列所肯定的徹底二叉樹的第一個非葉子節點開始,從右向左,從下往上,對每一個節點進行調整(大頂堆,小頂堆),直到無序序列中只剩下一個元素。
優勢: a )最壞狀況下時間複雜度也是 O(nlog2n) ,這是它相對快排最大的優勢。
b )空間複雜度爲 O(1) ,這是在全部時間複雜度爲 O(nlog2n) 中最小的。

適用於元素不少的場合,好比 100 萬個元素中選前 10 個最大的。
         堆排序相對快速排序: 1 、最好最壞狀況下時間複雜度都爲 O(nlog2n) ,不會出現快排最壞的 O(n2)    2 、堆排序所需的輔助空間少,是 O(1) ,而快排是 O(log2n)


4.    歸併 排序      O(nlog2n)       O(nlog2n)       O(nlog2n)

     採用分治法的思想。將n個元素的序列劃分爲兩個序列,再將兩個序列劃分爲4個序列,直到每一個序列只有一個元素,最後,再有序序列兩兩歸併成一個有序的序列。
   歸併排序時間複雜度與初始序列無關。都是 O(nlog2n) 。空間複雜度爲 O(n)
   內存空間不足的時候,可以並行計算的時候使用歸併排序。

//歸併,將有二個有序數列a[start…mid]和a[mid+1…end]合併。把結果放到temp裏面
void Merge(int a[],int temp[], int start, int mid, int end)
{
  int i = start, j=mid+1, k = start;
  while(i!=mid+1 && j!=end+1)
  {
      if(a[i] >a[j])
        temp[k++] = a[j++];     //從小到大排序,a[j]放入temp[k],而後j,k都後移一位
      else
        temp[k++] = a[i++];
  }
  while(i != mid+1)
      temp[k++] = a[i++];
  while(j != end+1)
      temp[k++] = a[j++];
  for(i=start; i<=end; i++)
      a[i] = temp[i];
}

//內部使用遞歸
void MergeSort(int a[], int tempArr[], int start, int end)
{
  int mid;
  if(start < end)
  {
      mid = (start+ end) / 2;
      MergeSort(a, temp, start, mid);
      MergeSort(a, temp, mid+1, end);
      Merge(a, temp, start, mid, end);
  }
}

  1. 基數排序
多關鍵字排序。兩種,最高位優先、最低位優先。 
適用場景:序列中元素個數不少,可是組成元素的關鍵字的取值範圍比較小。好比取值範圍 0~9.

總結
1 、平均時間複雜度爲 O(nlog2n)   快些歸隊
                      快速    希爾   歸併   堆排序
2 、不穩定       快些選
               快速   希爾   選擇類排序(簡單選擇、堆排序)
3 、特殊的空間複雜度    其餘都是 O(1)       快速 O(log2n)  歸併 O(n)
4 、一趟保證一個元素到底最終位置           交換類      選擇類
5 、比較次數與初始序列無關       簡單選擇         折半插入
6 、排序趟數與初始序列       交換類排序
7 、元素基本有序 ( 正序 )              直接插入         冒泡
8 、當數據規模 n 較小      直接插入排序   簡單選擇排序
9 、當數據規模 n 較大,採用時間複雜度爲 O(nlog2n) 的排序方法(快些歸隊)
相關文章
相關標籤/搜索