1. 程式人生 > >【java面試】演算法篇之堆排序

【java面試】演算法篇之堆排序

一、堆的概念

堆是一棵順序儲存的完全二叉樹。完全二叉樹中所有非終端節點的值均不大於(或不小於)其左、右孩子節點的值。

其中每個節點的值小於等於其左、右孩子的值,這樣的堆稱為小根堆;

其中每個節點的值大於等於其左、右孩子的值,這樣的堆稱為大根堆;

二、要點

1.將陣列構造成初始堆(若想升序則建立大根堆,若想降序,則建立小根堆)

從最後一個節點開始調整,得到初始堆。


2.堆排序處理

交換堆頂的元素和最後一個元素,此時最後一個位置作為有序區(有序區顯示為黃色),然後進行其他無序區的堆調整,重新得到大頂堆後,交換堆頂和倒數第二個元素的位置……


重複此過程:


最後,有序擴充套件完成即排序完成:


核心程式碼

public void HeapAdjust(int[] array, int parent, int length) {

    int temp = array[parent]; // temp儲存當前父節點

    int child = 2 * parent + 1; // 先獲得左孩子

 

    while (child < length) {

        // 如果有右孩子結點,並且右孩子結點的值大於左孩子結點,則選取右孩子結點

        if (child + 1 < length && array[child] < array[child + 1]) {

            child++;

        }

 

        // 如果父結點的值已經大於孩子結點的值,則直接結束

        if (temp >= array[child])

            break;

 

        // 把孩子結點的值賦給父結點

        array[parent] = array[child];

 

        // 選取孩子結點的左孩子結點,繼續向下篩選

        parent = child;

        child = 2 * child + 1;

    }

 

    array[parent] = temp;

}

 

public void heapSort(int[] list) {

    // 迴圈建立初始堆

    for (int i = list.length / 2; i >= 0; i--) {

        HeapAdjust(list, i, list.length - 1);

    }

 

    // 進行n-1次迴圈,完成排序

    for (int i = list.length - 1; i > 0; i--) {

        // 最後一個元素和第一元素進行交換

        int temp = list[i];

        list[i] = list[0];

        list[0] = temp;

 

        // 篩選 R[0] 結點,得到i-1個結點的堆

        HeapAdjust(list, 0, i);

        System.out.format("第 %d 趟: \t", list.length - i);

        printPart(list, 0, list.length - 1);

    }

}

演算法分析

堆排序演算法的總體情況

排序類別

排序方法

時間複雜度

  空間複雜度

    穩定性

      複雜性

平均情況

 最壞情況

 最好情況

選擇排序

堆排序

O(nlog2n)

  O(nlog2n)

  O(nlog2n)

O(1)

不穩定

較複雜