堆排序一種比較複雜的排序算法,它主要用到堆(Heap)這一數據結構。javascript
堆(Heap)是二叉樹的一類,徹底二叉樹,它的特色是:html
以下圖 java
堆又分爲git
堆排序的主要過程(以MaxHeap爲例):github
從第一個非葉子結點開始,從下至上,從右至左,對每個非葉子結點作shiftDown操做,因此shiftDown是一個關鍵過程。算法
其中,能夠利用數組結構來表示Heap,已知節點索引i, 其節點關係有segmentfault
參考中都給出了一些實現,不過,對於heapifyDown方法,推薦以下實現,來源於參考4,我的以爲從理解和結構上看都比較好。api
heapifyDown(customStartIndex = 0) {
// Compare the parent element to its children and swap parent with the appropriate
// child (smallest child for MinHeap, largest child for MaxHeap).
// Do the same for next children after swap.
// 當使用Heap排序時,頂部元素被賦值爲尾元素,此時,須要從頂向下從新建堆
let currentIndex = customStartIndex;
let nextIndex = null;
// 假設在MaxHeap中,節點初始關係爲P->C->C1, 首先進行堆構建,
// 繼續假設子節點C大於父節點P, 則須要將子節點C與父節點P進行交換,
// 父節點P下沉作爲子節點,此時新的節點關係爲C->P->C1,
// 若是C1>P,則須要繼續將節點P下沉,變爲C->C1->P
// 以上例子說明,只要一個節點位置發生變化,就須要逐層向下遞歸,以確保節點關係正確
// 此處的while循環就是這個道路,雖然上面只有一個參數customStartIndex, 但考慮
// 節點可能互換,就須要進行向下遞歸,把當前節點的全部節點都進行一次比較
while (this.hasLeftChild(currentIndex)) {
// 與二叉樹不一樣,Heap結構中,左右節點值的關係是不固定的
// 左節點可能小於右節點,也可能大於右節點,只能保證左右節點和父節點的值大於關係固定
// 取左右節點中,較大(For MaxHeap)或較小(For MinHeap)的值與父節點進行交換
if (
this.hasRightChild(currentIndex)
&& this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))
) {
nextIndex = this.getRightChildIndex(currentIndex);
} else {
nextIndex = this.getLeftChildIndex(currentIndex);
}
// 若是節點大小關係正確,說明不用進行節點互換,直接退出,
// 不然進行遞歸檢測與修正
if (this.pairIsInCorrectOrder(
this.heapContainer[currentIndex],
this.heapContainer[nextIndex],
)) {
break;
}
this.swap(currentIndex, nextIndex);
currentIndex = nextIndex;
}
}
複製代碼
參考1,2裏圖文都很詳細,推薦,其中實現形式,能夠本身再整理優化下數組
另外,我找到一個可視化工具,不只有Heap Sort, 還有Binary Tree,能夠上手測試,親身感覺,強烈推薦: btv.melezinek.cz/binary-heap…bash
堆排序是一種不穩定的排序方法, 對於相同的關鍵字可能出現排在後面的關鍵字被交換到前面來的狀況