插入排序—直接插入排序(Straight Insertion Sort)


基本思想:

將一個記錄插入到已排序好的有序表中,從而得到一個新,記錄數增1的有序表。即:先將序列的第1個記錄看成是一個有序的子序列,然后從第2個記錄逐個進行插插入到已入,直至整個序列有序為止。

要點:設立哨兵,作為臨時存儲和判斷數組邊界之用。

直接插入排序示例:

 

如果碰見一個和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后順序沒有改變,從原無序序列出去的順序就是排好序后的順序,所以插入排序是穩定的。

直接插入排序(straight insertion sort)的做法是:
每次從無序表中取出第一個元素,把它插入到有序表的合適位置,使有序表仍然有序。
 
第一趟比較前兩個數,然后把第二個數按大小插入到有序表中; 第二趟把第三個數據與前兩個數從后向前掃描,把第三個數按大小插入到有序表中;依次進行下去,進行了(n-1)趟掃描以后就完成了整個排序過程。
 
直接插入排序是由兩層嵌套循環組成的。外層循環標識並決定待比較的數值。內層循環為待比較數值確定其最終位置。直接插入排序是將待比較的數值與它的前一個數值進行比較,所以外層循環是從第二個數值開始的。當前一數值比待比較數值大的情況下繼續循環比較,直到找到比待比較數值小的並將待比較數值置入其后一位置,結束該次循環。
哨兵的作用



算法中引進的附加記錄R[0]稱監視哨或哨兵(Sentinel)。

哨兵有兩個作用:

① 進人查找(插入位置)循環之前,它保存了R[i]的副本,使不致於因記錄后移而丟失R[i]的內容;

② 它的主要作用是:在查找循環中"監視"下標變量j是否越界。一旦越界(即j=0),因為R[0].可以和自己比較,循環判定條件不成立使得查找循環結束,從而避免了在該循環內的每一次均要檢測j是否越界(即省略了循環判定條件"j>=1")。

注意:

① 實際上,一切為簡化邊界條件而引入的附加結點(元素)均可稱為哨兵。

【例】單鏈表中的頭結點實際上是一個哨兵

② 引入哨兵后使得測試查找循環條件的時間大約減少了一半,所以對於記錄數較大的文件節約的時間就相當可觀。對於類似於排序這樣使用頻率非常高的算法,要盡可能地減少其運行時間。所以不能把上述算法中的哨兵視為雕蟲小技,而應該深刻理解並掌握這種技巧。

  

 

算法的實現:

 
#include<iostream>
using namespace std;
int  main()
{
     int  a[]={ 98 , 76 , 109 , 34 , 67 , 190 , 80 , 12 , 14 , 89 , 1 };
     int  k=sizeof(a)/sizeof(a[ 0 ]);
     int  j;
     for ( int  i= 1 ;i<k;i++) //循環從第2個元素開始
     {
         if (a[i]<a[i- 1 ])
         {
             int move =a[i];
             for (j=i- 1 ;j>= 0  && a[j]>move;j--)//a[j]若小於要挪動的數,則是循環終止的條件
             {
                 a[j+ 1 ]=a[j];//將a[i]前元素向后挪動一個
             }
             a[j+ 1 ]=move; //此處就是a[j+1]=move;
         }
     }
     for ( int  f= 0 ;f<k;f++)
     {
         cout<<a[f]<< "  " ;
     }
     return  0 ;
}

 

效率:

時間復雜度:O(n^2).

其他的插入排序有二分插入排序,2-路插入排序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM