【筆記】表插入排序

Time-space發表於2017-11-03

  插入排序:將待排序元素分為已排序子集和未排序子集,一次從未排序子集中的一個元素插入已排序子集中,使已排序自己仍然有序;重複執行以上過程,指導所有元素都有序為止。

 #define SIZE 100 /* 靜態連結串列容量 */
 typedef int KeyType; /* 定義關鍵字型別為整型 */

 typedef struct
 {
   KeyType key; /* 關鍵字項 */
   InfoType otherinfo; /* 其它資料項,具體型別在主程中定義 */
 }RedType; /* 記錄型別 */

 typedef struct
 {
   RedType rc; /* 記錄項 */
   int next; /* 指標項 */
 }SLNode; /* 表結點型別 */

 typedef struct
 {
   SLNode r[SIZE]; /* 0號單元為表頭結點 */
   int length; /* 連結串列當前長度 */
 }SLinkListType; /* 靜態連結串列型別 */

  基本演算法思想:假設以上述說明的靜態連結串列型別作為待排記錄序列的儲存結構,並且為了插入方便起見,設陣列中下標為0的分量為表頭結點,並令表頭結點記錄的關鍵字取最大整數MAXINT。則表插入排序的過程描述如下:首先將靜態連結串列中陣列下標為1的分量和表頭結點構成一個迴圈連結串列,然後依次將下標為2至n的分量(結點)按記錄關鍵字非遞減有序插入到迴圈連結串列中。

  以序列(49,38,65,97,76,13,27,49)為例,表插入排序的過程如下圖所示。


這裡寫圖片描述

  從表插入排序的過程可見,表插入排序的基本操作仍是將一個記錄插入到已排好序的有序表中。和直接插入排序相比,不同之處僅是修改2n次指標值代替移動記錄,排序過程中所需進行的關鍵字間的比較次數相同。因此表插入排序的時間複雜度仍是O(n2)

O(n^2)

  表插入排序的結果只是求得一個有序連結串列,則只能對它進行順序查詢,不能進行隨機查詢,為了能實現有序表的折半查詢,尚需對記錄進行重新排列。
  重排記錄的做法:順序掃描有序連結串列,將連結串列中的第i個結點移動至陣列的第i個分量中。如下圖所示,(a)是經表插入排序後得到的有序連結串列SL。根據頭結點中指標域的指示,連結串列的第一個結點,即關鍵字最小的結點是陣列中下標為6的分量,其中記錄應移動至陣列的第一個分量中,則將SL.r[1]和SL.r[6]互換,並且為了不中斷靜態連結串列中的鏈,即在繼續順鏈掃描時仍能找到互換之前在SL.r[1]中的結點,令互換之後的SL.r[1]中指標域的值修改為6。推廣至一般情況,若第i個最小關鍵字的結點是陣列中下標為p

p
p>i
p >i
的分量,則互換SL.r[i]和SL.r[p],且令SL.r[i]中指標域的值改為p;由於此時陣列中所有小於i的分量中已是“到位”的記錄,則當p<i
p <i
時,應順鏈繼續查詢直到pi
p \geq i
為止。


這裡寫圖片描述

  • 標頭檔案
 #define MAXSIZE 20 /* 一個用作示例的小順序表的最大長度 */
 typedef int InfoType; /* 定義其它資料項的型別 */
 typedef int KeyType; /* 定義關鍵字型別為整型 */
 typedef struct
 {
   KeyType key; /* 關鍵字項 */
   InfoType otherinfo; /* 其它資料項,具體型別在主程中定義 */
 }RedType; /* 記錄型別 */

 typedef struct
 {
   RedType r[MAXSIZE+1]; /* r[0]閒置或用作哨兵單元 */
   int length; /* 順序表長度 */
 }SqList; /* 順序表型別 */
  • 函式檔案
 void TableInsert(SLinkListType *SL,RedType D[],int n)
 { /* 由陣列D建立n個元素的表插入排序的靜態連結串列SL */
   int i,p,q;
   (*SL).r[0].rc.key=INT_MAX; /* 表頭結點記錄的關鍵字取最大整數(非降序連結串列的表尾) */
   (*SL).r[0].next=0; /* next域為0表示表尾(現為空表,初始化) */
   for(i=0;i<n;i++)
   {
     (*SL).r[i+1].rc=D[i]; /* 將陣列D的值賦給靜態連結串列SL */
     q=0;
     p=(*SL).r[0].next;
     while((*SL).r[p].rc.key<=(*SL).r[i+1].rc.key)
     { /* 靜態連結串列向後移 */
       q=p;
       p=(*SL).r[p].next;
     }
     (*SL).r[i+1].next=p; /* 將當前記錄插入靜態連結串列 */
     (*SL).r[q].next=i+1;
   }
   (*SL).length=n;
 }

 void Arrange(SLinkListType *SL)
 { /* 根據靜態連結串列SL中各結點的指標值調整記錄位置,使得SL中記錄按關鍵字 */
   /* 非遞減有序順序排列  */
   int i,p,q;
   SLNode t;
   p=(*SL).r[0].next; /* p指示第一個記錄的當前位置 */
   for(i=1;i<(*SL).length;++i)
   { /* (*SL).r[1..i-1]中記錄已按關鍵字有序排列,第i個記錄在SL中的當前位置應不小於i */
     while(p<i)
       p=(*SL).r[p].next; /* 找到第i個記錄,並用p指示其在SL中當前位置 */
     q=(*SL).r[p].next; /* q指示尚未調整的表尾 */
     if(p!=i)
     {
       t=(*SL).r[p]; /* 交換記錄,使第i個記錄到位 */
       (*SL).r[p]=(*SL).r[i];
       (*SL).r[i]=t;
       (*SL).r[i].next=p; /* 指向被移走的記錄,使得以後可由while迴圈找回 */
     }
     p=q; /* p指示尚未調整的表尾,為找第i+1個記錄作準備 */
   }
 }

 void Sort(SLinkListType L,int adr[])
 { /* 求得adr[1..L.length],adr[i]為靜態連結串列L的第i個最小記錄的序號 */
   int i=1,p=L.r[0].next;
   while(p)
   {
     adr[i++]=p;
     p=L.r[p].next;
   }
 }

 void Rearrange(SLinkListType *L,int adr[])
 { /* adr給出靜態連結串列L的有序次序,即L.r[adr[i]]是第i小的記錄。 */
   /* 按adr重排L.r,使其有序. */
   int i,j,k;
   for(i=1;i<(*L).length;++i)
     if(adr[i]!=i)
     {
       j=i;
       (*L).r[0]=(*L).r[i]; /* 暫存記錄(*L).r[i] */
       while(adr[j]!=i)
       { /* 調整(*L).r[adr[j]]的記錄到位直到adr[j]=i為止 */
         k=adr[j];
         (*L).r[j]=(*L).r[k];
         adr[j]=j;
         j=k; /* 記錄按序到位 */
       }
       (*L).r[j]=(*L).r[0];
       adr[j]=j;
     }
 }

 void print(SLinkListType L)
 {
   int i;
   for(i=1;i<=L.length;i++)
     printf("key=%d ord=%d next=%d\n",L.r[i].rc.key,L.r[i].rc.otherinfo,L.r[i].next);
 }
  • 主程式
 #include<limits.h>
 #define N 8
 void main()
 {
   RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
   SLinkListType l1,l2;
   int *adr,i;
   TableInsert(&l1,d,N);
   l2=l1; /* 複製靜態連結串列l2與l1相同 */
   printf("排序前:\n");
   print(l1);
   Arrange(&l1);
   printf("l1排序後:\n");
   print(l1);
   adr=(int*)malloc((l2.length+1)*sizeof(int));
   Sort(l2,adr);
   for(i=1;i<=l2.length;i++)
     printf("adr[%d]=%d ",i,adr[i]);
   printf("\n");
   Rearrange(&l2,adr);
   printf("l2排序後:\n");
   print(l2);
 }
  • 測試結果


這裡寫圖片描述

相關文章