【筆記】樹形選擇排序

Time-space發表於2017-11-05

  樹形選擇排序:又稱為錦標賽排序,是一種按照錦標賽的思想進行選擇排序的方法。

  基本演算法思想:首先對n個記錄的關鍵字進行兩兩比較,然後在其中[n2

\frac {n}{2}
]個較小者之間再進行兩兩比較,如此重複,直至選出最小關鍵字的記錄為止。這個過程可用一棵有n個葉子結點的完全二叉樹表示。

  如下圖所從8個關鍵字中選擇出最小關鍵字的過程。8個葉子結點中一次存放排序之前的8個關鍵字,每個非終端結點中的關鍵字均等於其左、右孩子結點中較小的關鍵字,則根結點中的關鍵字即為葉子結點中的最小關鍵字。在輸出最小關鍵字之後,根據關係的可傳遞性,預選出次小關鍵字,僅需將葉子結點中的最小關鍵字改為“最大值”,然後從該葉子結點開始,和其左(或右)兄弟的關鍵字進行比較,修改從葉子結點到根的路徑上各結點的關鍵字,則根結點的關鍵字即為次小關鍵字。同理,依次可選出從小到大的所有關鍵字。


這裡寫圖片描述

  由於含有n個葉子結點的完全二叉樹的深度為[log2n

log_2 n
]+1,則在樹形選擇排序中,除了最小關鍵字之外,每選擇一個次小關鍵字僅需進行[log2n
log_2 n
]次比較,因此它的時間複雜度為O(nlogn)
O(nlogn)
。但是這種排序方法尚有輔助儲存空間較多、和最大值進行多餘的比較等缺點。為了彌補可以使用另一種形式的選擇排序——堆排序。

  • 型別定義
 #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 TreeSort(SqList *L)
 { /* 樹形選擇排序 */
   int i,j,j1,k,k1,l,n=(*L).length;
   RedType *t;
   l=(int)ceil(log(n)/log(2))+1; /* 完全二叉樹的層數 */
   k=(int)pow(2,l)-1; /* l層完全二叉樹的結點總數 */
   k1=(int)pow(2,l-1)-1; /* l-1層完全二叉樹的結點總數 */
   t=(RedType*)malloc(k*sizeof(RedType)); /* 二叉樹採用順序儲存結構 */
   for(i=1;i<=n;i++) /* 將L.r賦給葉子結點 */
     t[k1+i-1]=(*L).r[i];
   for(i=k1+n;i<k;i++) /* 給多餘的葉子的關鍵字賦無窮大 */
     t[i].key=INT_MAX;
   j1=k1;
   j=k;
   while(j1)
   { /* 給非葉子結點賦值 */
     for(i=j1;i<j;i+=2)
       t[i].key<t[i+1].key?(t[(i+1)/2-1]=t[i]):(t[(i+1)/2-1]=t[i+1]);
     j=j1;
     j1=(j1-1)/2;
   }
   for(i=0;i<n;i++)
   {
     (*L).r[i+1]=t[0]; /* 將當前最小值賦給L.r[i] */
     j1=0;
     for(j=1;j<l;j++) /* 沿樹根找結點t[0]在葉子中的序號j1 */
       t[2*j1+1].key==t[j1].key?(j1=2*j1+1):(j1=2*j1+2);
     t[j1].key=INT_MAX;
     while(j1)
     {
       j1=(j1+1)/2-1; /* 序號為j1的結點的雙親結點序號 */
       t[2*j1+1].key<=t[2*j1+2].key?(t[j1]=t[2*j1+1]):(t[j1]=t[2*j1+2]);
     }
   }
   free(t);
 }
  • 主程式
 #include<limits.h> /* INT_MAX等 */
 #define N 8
 void print(SqList L)
 {
   int i;
   for(i=1;i<=L.length;i++)
     printf("(%d,%d)",L.r[i].key,L.r[i].otherinfo);
   printf("\n");
 }


 void main()
 {
   RedType d[N]={{49,1},{38,2},{65,3},{97,4},{76,5},{13,6},{27,7},{49,8}};
   SqList l;
   int i;
   for(i=0;i<N;i++)
     l.r[i+1]=d[i];
   l.length=N;
   printf("排序前:\n");
   print(l);
   TreeSort(&l);
   printf("排序後:\n");
   print(l);
 }
  • 測試結果


這裡寫圖片描述

相關文章