【排序算法】堆排序原理及Java實現

1、基本思想

堆是一種特殊的樹形數據結構,其每個節點都有一個值,通常提到的堆都是指一顆完全二叉樹,根結點的值小於(或大於)兩個子節點的值,同時,根節點的兩個子樹也分別是一個堆。
這裏寫圖片描述
堆排序就是利用堆(假設利用大頂堆)進行排序的方法。它的基本思想是,將待排序的序列構造成一個大頂堆。此時,整個序列的最大值就是堆頂的根節點。將它移走(其實就是將其與堆數組的末尾元素交換,此時末尾元素就是最大值),然後將剩餘的 n-1 個序列重新構造成一個堆,這樣就會得到 n 個元素中次大的值。如此反覆執行,便能得到一個有序序列了。
堆排序的實現需要解決的兩個關鍵問題:
(1)將一個無序序列構成一個堆。
(2)輸出堆頂元素後,調整剩餘元素成爲一個新堆。

2、複雜度分析

堆排序的運行時間主要耗費在初始構建堆和在重建堆時反覆篩選上。在構建對的過程中,因爲我們是完全二叉樹從最下層最右邊的非終端節點開始構建,將它與其孩子進行比較和若有必要的互換,對每個非終端節點來說,其實最多進行兩次比較和互換操作,因此整個構建堆的時間複雜度爲O(n)
在正式排序時,第i次取堆頂記錄重建堆需要用O(logi)的時間(完全二叉樹的某個節點到根節點的距離爲這裏寫圖片描述),並且需要取n-1次堆頂記錄,因此,重建堆的時間複雜度爲O(nlogn)
所以總體來說,堆排序的時間複雜度爲O(nlogn),由於堆排序對原始記錄的狀態並不敏感,因此它無論是最好、最壞和平均時間複雜度均爲O(nlogn)。這在性能上顯然要遠遠好過於冒泡、簡單選擇、直接插入的時間複雜度了。
空間複雜度上,它只有一個用來交換的暫存單元,也非常的不錯。不過由於記錄的比較與交換是跳躍式進行的,因此堆排序也是一種不穩定的排序方法。
另外,由於出事構建堆所需要的比較次數比較多,因此,他並不適合待排序序列個數較少的情況。

3.大根堆排序算法的基本操作

① 初始化操作:將R[1..n]構造爲初始堆;
②每一趟排序的基本操作:將當前無序區的堆頂記錄R[1]和該區間的最後一個記錄交換,然後將新的無序區調整爲堆(亦稱重建堆)。

注意:
①只需做n-1趟排序,選出較大的n-1個關鍵字即可以使得文件遞增有序。
②用小根堆排序與利用大根堆類似,只不過其排序結果是遞減有序的。堆排序和直接選擇排序相反:在任何時刻堆排序中無序區總是在有序區之前,且有序區是在原向量的尾部由後往前逐步擴大至整個向量爲止。

4、Java實現如下

public class HeapSort {
    /**
     * 構建大頂堆
     */
    public static void adjustHeap(int[] a, int i, int len) {
        int temp, j;
        temp = a[i];
        for (j = 2 * i; j < len; j *= 2) {// 沿關鍵字較大的孩子結點向下篩選
            if (j < len && a[j] < a[j + 1])
                ++j; // j爲關鍵字中較大記錄的下標
            if (temp >= a[j])
                break;
            a[i] = a[j];
            i = j;
        }
        a[i] = temp;
    }

    public static void heapSort(int[] a) {
        int i;
        for (i = a.length / 2 - 1; i >= 0; i--) {// 構建一個大頂堆
            adjustHeap(a, i, a.length - 1);
        }
        for (i = a.length - 1; i >= 0; i--) {// 將堆頂記錄和當前未經排序子序列的最後一個記錄交換
            int temp = a[0];
            a[0] = a[i];
            a[i] = temp;
            adjustHeap(a, 0, i - 1);// 將a中前i-1個記錄重新調整爲大頂堆
        }
    }

    public static void main(String[] args) {
        int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
        heapSort(a);
        System.out.println(Arrays.toString(a));
    }
} 
發佈了53 篇原創文章 · 獲贊 559 · 訪問量 88萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章