1. 程式人生 > >排序演算法之一--直接插入排序

排序演算法之一--直接插入排序

直接插入排序中加入了附加記錄,又稱監視哨或者哨兵。

哨兵的主要作用:

        ① 進人查詢(插入位置)迴圈之前,它儲存了R[i]的副本,使不致於因記錄後移而丟失R[i]的內容;
      ② 它的主要作用是:在查詢迴圈中監視下標變數j是否越界。一旦越界(即j=0),因為R[0].可以和自己比較,迴圈判定條件不成立使得查詢迴圈結束,從而避免了在該迴圈內的每一次均要檢測j是否越界(即省略了迴圈判定條件j>=1)。

      下面的c函式,是基礎的直接插入排序,但是更容易幫助理解哨兵的意思

void insert_sort(int a[],int n)

//待排序元素用一個數組a表示,陣列有

n個元素

{

    int i,j;

    int temp;

    for ( i=1; i<n; i++) //i表示插入次數,共進行n-1次插入

  {

      temp=a[i]; //把待排序元素賦給temptempwhile迴圈中並不改變,這樣方便比較,並且它是要插入的元素

      j=i-1;

      //while迴圈的作用是將比當前元素大的元素都往後移動一個位置

      while ((j>=0)&& (temp<a[j])){

          a[j+1]=a[j];

          j--; // 順序比較和移動

,依次將元素後移動一個位置

          }

      a[j+1]=temp;//元素後移後要插入的位置就空出了,找到該位置插入

  }

}

          上面的temp就相當於哨兵的意思

          下面是改進版的演算法:

   void lnsertSort(SeqList R)
   {                                                     //對順序表R中的記錄R[1..n]按遞增序進行插入排序
    int i,j;
    for(i=2;i<=n;i++)                         //依次插入R[2],…,R[n]


      if(R[i].key<R[i-1].key){                //若R[i].key大於等於有序區中所有的keys,則R[i]
                                                         //應在原有位置上
        R[0]=R[i];j=i-1;                          //R[0]是哨兵,且是R[i]的副本
        do{                                            //從右向左在有序區R[1..i-1]中查詢R[i]的插入位置
         R[j+1]=R[j];                            //將關鍵字大於R[i].key的記錄後移
         j-- ;
         }while(R[0].key<R[j].key);      //當R[i].key≥R[j].key時終止
        R[j+1]=R[0];                            //R[i]插入到正確的位置上
       }//endif
   }

   演算法用c語言實現了,現在來分析一下時間複雜度和空間複雜度

   從空間上:

           只需要一個哨兵來輔助,因此空間複雜度為O(1)

   從時間上:

           最好的情況:所有的序列本來就是是需要的序列(順序或者逆序),但還是需要遍歷一遍所有元素,那個器時間複雜度為O(n)

           最壞的情況:所有的序列和需要的序列恰恰相反,需要(1,2,3,4,5),原序列是(5,4,3,2,1),那就需要在遍歷每一個元素的時候,要進行一波與前面元素的交換,此時的時間複雜度為2+3+4+...+n 其時間複雜度為O(n2)

           一般情況:排序記錄是隨機的,

     穩定性:穩定的