樹形選擇排序(錦標賽排序)


介紹:

  樹形選擇排序(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) ,只相對前面的減少了一半遍歷次數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM