介紹:
樹形選擇排序(Tree Selection Sort),又稱錦標賽排序(Tournament Sort),是一種按錦標賽的思想進行選擇排序的方法。簡單選擇排序花費的時間主要在比較上,每次都會進行很多重復的比較,造成浪費時間。錦標賽排序就是通過記錄比較結果,減少比較次數,從而降低時間復雜度。
算法描述:
首先對n個記錄的關鍵字進行兩兩比較,然后再對勝者進行兩兩比較,如此重復,直至選出最小關鍵字的記錄為止。這個過程可用一棵有n個葉子結點的完全二叉樹描述。
圖片演示:
用錦標賽排序對下圖序列排序。
兩兩比較構造完全二叉樹。
選出最小值,並修改該葉節點關鍵字為∞。
重復上述過程,直至葉節點全為∞,排序完成。
性能分析:
時間復雜度:O(NlogN)
空間復雜度:O(N)
穩定性:不穩定
缺點:輔助存儲空間較多,和∞的比較多余。
為了彌補這些缺點,威洛姆斯(J·willioms)在1964年提出了另一種形式的選擇排序——堆排序。
代碼實現:
// Java代碼 class TreeSelectionSort { 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 int maxIndex; //堆最大值所對應的葉子節點的下標 //繼續尋找剩下的最大值,逆向存儲,升序排序 for (int i = data.length-2; i >=0; i--) { 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 } } }
算法優化:
上面代碼一次遍歷只是找出未排序序列中的最小值,其實我們可以在遍歷過程中同時找出最小值和最大值,並把每次找出的最大值按順序放到每次排列數據的末尾。時間復雜度還是 O(N^2) ,只相對前面的減少了一半遍歷次數。