1. 程式人生 > >Java排序演算法 [堆排序]

Java排序演算法 [堆排序]

package cn.com.dom4j.sort;

import java.util.Arrays;

public class Test2 {

    /**
     * 堆排序
     */
    public static <AnyType extends Comparable<? super AnyType>> void heapSort(AnyType[] a) {

        // buildHeap
        for (int i = a.length / 2; i >= 0; i--) {
            // 將陣列值按初始順序放入堆中, 從根節點執行下濾操作將構建一個堆
            percolateDown(a, i, a.length);
        }

        // deleteMax
        for (int i = a.length - 1; i > 0; i--) {
            // 在構建了一個 max堆後, 將根節點與最後一個元素互換, 同時將堆的大小 -1, 調整位置, 再次實現堆序
            // 這樣每互換一次, 最大的元素就會放在堆的後面 (已經從堆中刪除, 不屬於堆了), 堆後面的元素會保持順序, 直到堆中只剩一個元素為止
            swap(a, 0, i);
            percolateDown(a, 0, i);
        }

    }

    /**
     * 下濾操作: 調整某個節點的位置, 以保持堆序
     * @param a 待排序序列
     * @param i 要調整的節點在陣列中的索引
     * @param n 堆的大小 (堆中元素個數)
     */
    private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n) {

        int child;
        AnyType tmp;

        // tmp記錄被調整元素的值, i的值隨 child不斷改變, 直到比較完所有的子節點 (leftChild(i) < n) 為止
        for (tmp = a[i]; leftChild(i) < n; i = child) {
            child = leftChild(i);
            // child == n - 1時, 其左子節點為堆的最後一個元素, 沒有右節點, 無須比較
            // 將該節點與其左右節點比較, 記錄其中最小的節點的索引
            if (child != n - 1 && a[child].compareTo(a[child + 1]) < 0) {
                child++;
            }
            // 將需要被調整和節點與其子節點進行比較, 如果小於子節點, 當前節點的值替換為子節點的值 (注意不是交換)
            if (tmp.compareTo(a[child]) < 0) {
                a[i] = a[child];
            } else {
                break;
            }
        }
        // 找到合適的位置後, 直接賦值來避免多餘的交換操作
        a[i] = tmp;
    }

    /**
     * 獲取某個節點的左子節點在陣列中的索引, 因為是從 0開始的, 所以要 +1
     */
    private static int leftChild(int i) {
        return 2 * i + 1;
    }


    /**
     * 交換陣列中兩個元素的位置
     */
    public static <AnyType extends Comparable<? super AnyType>> void swap(AnyType[] arr, int i, int j) {
        if (arr == null || arr.length <= 1 || i == j) {
            return;
        }

        AnyType tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}