插入排序

基本思想

每趟將一個待排序的對象,按其關鍵碼大小,插入到前面已經排序好的一組對象的適當位置
,直到對象全部插入爲止。

即邊插入邊排序,保證子序列中隨時都是排好序的

插入排序算法的分類

直接插入排序

折半插入排序

希爾排序

直接插入排序

排序過程:整個排序過程爲n-1趟插入,即先將序列中第1個記錄看成是一個有

序子序列,然後從第2個記錄開始,逐個進行插入,直至整個序列有序。
這裏寫圖片描述
void InsertSort(SqList &L)
{
int i,j;

  for(i=2;i<L.length;++i)

  if(L.r[i].key<L.r[i-1].key)        //"<",需將r[i]插入有序子表
  {            
  L.r[0]=L.r[i];      //將待插入的記錄暫時存在監視崗哨中

  L.r[i]=L.r[i-1];     //r[i-1]後移

  for(j=i-2;L.r[0].key<L.r[j].key;--j)//從後向前尋找插入位置
  {

   L.r[j+1]=L.r[j];//記錄逐個後移,直到找到插入位置

  }

  L.r[j+1]=L.r[0];    //將r[0]即原r[i],插入到正確位置
  }
}

算法分析

設對象個數爲n,則執行n-1趟

比較次數和移動次數與初始排序有關

最好情況下:

  • 每趟只需要比較1次,不移動

  • 總比較次數爲n-1
    這裏寫圖片描述

最壞情況下:第i趟比較i次,移動i+1次

這裏寫圖片描述

比較次數:KCN=(n+2)(n-1)/2=n*n/2

移動次數:RMN=(n+4)(n-1)/2=n*n/2

算法分析

  • 若出現各種可能排序的概率相同,則可取最好情況和最壞情況的平均情況
    平均情況比較次數和移動次數爲n*n/4

  • 時間複雜度爲O(n*n)

  • 空間複雜度爲O(1)

  • 是一種穩定的排序方法

折半插入排序

折半插入排序建立在直接插入排序的基礎上,是它的拓展出來的東西.

我們在將一個新元素插入已經排好序的數組的過程中,尋找插入點時,將待插入

區域的上限設置爲a[low],下限設置爲a【high】,然後將待插入元素與區間中間

位置a[m]進行比較,其中m=(low+high)/2

如果比中間位置a[m]小,則選擇a[low]到a[m-1]爲新的插入區域(即high=m-1),

如果比中間位置a[m]大,則選擇a[m+1]到a[high]爲新的插入區域(即low=m+1)

(3)如此直至low<=high不成立,即將此位置之後所有元素後移一位,並將新元素插入a[high+1]

Void BInserSort(SqList &L)
{
  for(i=2;i<L.Length;++i)//對順序表L做折半插入排序
  {
   L.r[0]=L.r[i];//將待插入的記錄暫存到監視哨中
   low=1;high=i-1;//置查找區間初值
   while(low<=high)  //在r[low.high]中折半查找插入的位置
   {
m=(low+high)/2   //折半
if(L.r[0].key<L.r[m].Key) high=m-1;//插入點在前一個子表
else low=m+1;      //插入點在後一子表
   }
   for(j=i-1;j>high+1;--j) L.r[j+1]=L.r[j];//記錄後移
   L.r[high+1]=L.r[0];   //將r[0]即原r【i】,插入到正確位置
  }

}

算法分析

折半查找比順序查找快,所以折半插入排序就平均性能來說比直接插入排序要快

它所需要的關鍵碼比較次數與待排序對象序列的初始化排列無關,僅依賴於對象個數。在插入第i個對象時,需要經過log2i+1次關鍵碼比較,才能確定它應插入的位置

當n較大時,總關鍵碼比較次數比直接插入排序的最壞情況要好得多,但其最好的情況要差

在對象的初始排列已經按關鍵碼排好序或接近有序時,直接插入排序比折半

插入排序執行的關鍵碼比較次數要少

折半插入排序的對象移動次數與直接插入排序相同,依賴於對象的初始排列

  • 減少了比較次數,但沒有減少移動次數

  • 平均性能優於直接插入排序

  • 時間複雜度爲O(n*n)

  • 空間複雜度爲O(1)

  • 是一種穩定的排序方法

  • 只能用於順序結構,不能用於鏈式結構

  • 適合初始記錄無序,n較大的情況

希爾排序

希爾排序是1959年由D.L.Shell提出來的,相對直接插入排序有較大的改進。希爾排序又叫縮小增量排序。

算法思想的出發點:

直接插入排序在基本有序時,效率較高

在待排序的記錄個數較少時,效率較高

基本思想:

先將整個待排記錄序列按某個增量d分割成若干組子序列,每組中記錄的下標

相差d,分別對每組進行直接插入排序,然後再用一個較小的增量對它進行分

組,在每組中再進行直接插入排序。這樣當經過幾次分組排序後,待整個序

列中的記錄“基本有序”時,再對全體記錄進行一次直接插入排序。

這裏寫圖片描述

技巧:

子序列的構成不是簡單地“逐段分割”將相隔某個增量dk的記錄組成一組子序

列讓增量dk逐趟縮短(例如依次取5,3,1)

直到dk=1爲止。

優點:

  • 小元素跳躍式前移

  • 最後一趟增量爲1時,序列已基本有序

  • 平均性能優於直接插入排序

    void ShellInsert(SqList &L,int dk)
    {
     for(i=dk+1;i<=L.length;++i)
    
     if(L.r[i].Key<L.r[i-dk].key)
     {
      L.r[0]=L.r[i];
      for(j=i-dk;j>0&&L.r[0].key<L.r[j].key;j-=dk)
      {
        L.r[j+dk]=L.r[j];
    
      }
         L.r[j+dk]=L.r[0];
      }
    
    }
    
    void ShellSort(SqList &L,int dt[],int t)
    {
     for(k=0;k<t;++k)
     {
    
          ShellInsert(L,dt[k]);
         }
    }
    
發佈了134 篇原創文章 · 獲贊 184 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章