【算法四】堆排序

基本思路

  • 1.若array[0,…,n-1]表示一顆完全二叉樹的順序存儲模式,則雙親節點指針和孩子結點指針之間的內在關係如下:
任意一節點指針 i:
父節點:i==0 ? null : (i-1)/2
左孩子:2*i + 1
右孩子:2*i + 2
  • 2.堆得定義
n個關鍵字序列array[0,...,n-1],當且僅當滿足下列要求:(0 <= i <= (n-1)/2)
① array[i] <= array[2*i + 1] 且 array[i] <= array[2*i + 2]; 稱爲小根堆;
② array[i] >= array[2*i + 1] 且 array[i] >= array[2*i + 2]; 稱爲大根堆;
  • 3.建立大頂堆 n個節點的完全二叉樹array[0,…,n-1],最後一個節點n-1是第(n-1-1)/2個節點的孩子。對第(n-1-1)/2個節點爲根的子樹調整,使該子樹稱爲堆。

對於大根堆,調整方法爲:若【根節點的關鍵字】小於【左右子女中關鍵字較大者】,則交換。

之後向前依次對各節點((n-2)/2 - 1)~ 0爲根的子樹進行調整,看該節點值是否大於其左右子節點的值,若不是,將左右子節點中較大值與之交換,交換後可能會破壞下一級堆,於是繼續採用上述方法構建下一級的堆,直到以該節點爲根的子樹構成堆爲止。

反覆利用上述調整堆的方法建堆,直到根節點。

  • 4.堆排序(大頂堆)
①將存放在array[0,...,n-1]中的n個元素建成初始堆;
②將堆頂元素與堆底元素進行交換,則序列的最大值即已放到正確的位置;
③將數組中array[0,...,n-1]前n-1個元素再次形成大根堆,再重複第②③步,直到堆中僅剩下一個元素爲止。

代碼實現


/**
    *  大頂堆排序
    * @param array
    */
public static void maxHeapSort(int[] array) {
    int i;
    int len = array.length;
    // 構建大頂堆
    for (i = len / 2 - 1; i >= 0; i--) {
        adjustMaxHeap(array, i, len);
    }
    // 堆頂是最大值,交換堆頂和最後一個數,再重新調整最大堆,下一次循環   i--
    for (i = len - 1; i >= 0; i--) {
        int temp = array[0];
        array[0] = array[i];
        array[i] = temp;
        adjustMaxHeap(array, 0, i);
    }
    System.out.println(Arrays.toString(array));
}

private static void adjustMaxHeap(int[] a, int pos, int len) {
    int temp;
    int child;
    for (temp = a[pos]; 2 * pos + 1 < len; pos = child) {
        // 數組從0開始,r(i)>=r(2i) r(i)>=r(2i+1)  對應 pos => 2 * pos + 1 和 2 * pos +2
        child = 2 * pos + 1;
        // 有右孩子,且右孩子數值更大
        if (child + 1 < len && a[child] < a[child + 1]) {
            child++;
        }
        // 最大的孩子大於根節點
        if (a[child] > temp) {
            a[pos] = a[child];
        } else {
            break;
        }
    }
    a[pos] = temp;
}

時間複雜度和空間複雜度

時間複雜度:建堆:o(n),每次調整o(log n),故最好、最壞、平均情況下:o(n*logn)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章