1. 程式人生 > >算法二之樹形選擇排序

算法二之樹形選擇排序

com 二叉樹 關系 賦值 public 堆排 lec style value

一、樹形選擇排序的基本思想

(1) 樹形選擇排序又稱錦標賽排序(Tournament Sort),是一種按照錦標賽的思想進行選擇排序的方法。首先對n個記錄的關鍵字進行兩兩比較,然後在n/2個較小者之間再進行兩兩比較,如此重復,直至選出最小的記錄為止。

(2) 樹形選擇排序(Tree Selection Sort),這個過程可用一棵有n個葉子結點的完全二叉樹表示。 技術分享

例如,圖表中的二叉樹表示從8個數中選出最小數的過程。

8個葉子結點到根接點中的關鍵字,每個非終端結點中的數均等於其左右孩子結點中較小的數值,則根結點中的數即為葉子結點的最小數。在輸出最小數之後,割據關系的可傳遞性,欲選出次小數,僅需將葉子結點中的最小數(13)改為“最大值”

,然後從該葉子接點開始,和其左(或右)兄弟的數值進行比較,修改從葉子結點到根的路徑上各結點的數,則根結點的數值即為最小值。同理,可依次選出從小到大的所有數。

(3) 由於含有n個子結點的完全二叉樹的深度為log2n+1,則在樹形選擇排序中,除了最小數值之外,每選擇一個次小數僅需要進行log2n次比較,因此,它的時間復雜度為O(nlogn)。但是,這種排序方法尚輔助存儲空間較多、和“最大值”進行多余比較等缺點。為了彌補,威洛姆斯(J. willioms)在1964年提出了另一種形式的選擇排序——堆排序。

二、算法實現

算法從葉子節點中選出最大值,逆向存儲在數據隊列中,形成升序排序。

 public
static void treeSelectionSort(int[] data) { //長度小於2,無需排序 if(data.length<2){ return; } int leafCount = 1; //完全二叉樹的葉子節點數 //算出完全二叉樹的葉子節點數 while (leafCount < data.length) { leafCount *= 2; } int[] tree = new
int[leafCount * 2]; //樹,tree[0]不存儲數據 //data裏面的值賦值到樹葉子節點 for (int i = 0; i < data.length; i++) { tree[tree.length - i - 1] = data[i]; } //初始化沒有賦值的樹葉子結點,賦值葉子節點最小值 for (int i = data.length; i < leafCount; i++) { tree[tree.length - i - 1] = Integer.MIN_VALUE; } //初始化,構建整棵樹 for (int i = tree.length - 1; i > 1; i -= 2) { tree[i / 2] = Math.max(tree[i], tree[i - 1]); } data[data.length-1] = tree[1]; //將樹根節點賦值於data //繼續尋找剩下的最大值,逆向存儲,升序排序 for (int i = data.length-2; i >=0; i--) { int maxIndex = tree.length - 1; //樹根值所在的葉子節點的位置 //尋找樹根值所在的葉子節點的位置 while (tree[maxIndex] != tree[1]) { maxIndex--; } tree[maxIndex]=Integer.MIN_VALUE; //該葉子節點賦值最小值 //調整樹,根節點值最大 while(maxIndex>1){ //左葉子結點 if (maxIndex % 2 == 0) { tree[maxIndex / 2] = Math.max(tree[maxIndex] ,
tree[maxIndex + 1]); } else { tree[maxIndex / 2] = Math.max(tree[maxIndex] ,
tree[maxIndex - 1]); } maxIndex/=2;//指向父節點 } data[i] = tree[1]; //將樹根節點賦值於data } }

算法二之樹形選擇排序