Heap sort
流程:
- 透過 heapify 將陣列轉換為 heap 結構
- 以遞增排序為例,透過 max-heap 的性值,將第一筆與最後一筆元素交換,即確定了排序後的位置
- 排除已排序的元素,重複上述步驟直到 max-heap size 為 1
javascript
1heapSort([5, 3, 2, 10, 1, 9, 8, 6, 4, 7]);23function heapSort(array) {4for (let i = Math.floor(array.length / 2) - 1; i >= 0; i--) {5maxHeapify(array, i, array.length);6}78for (let i = array.length - 1; i > 0; i--) {9const lesser = array[i];10array[i] = array[0];11array[0] = lesser;12maxHeapify(array, 0, i);13}1415return array;16}171819const leftIndex = 2 * index + 1;20const rightIndex = 2 * index + 2;21let largestValueIndex = index;2223if (24heapSize > leftIndex &&25array[largestValueIndex] < array[leftIndex]26) {27largestValueIndex = leftIndex;28}2930if (31heapSize > rightIndex &&32array[largestValueIndex] < array[rightIndex]33) {34largestValueIndex = rightIndex;35}3637if (index !== largestValueIndex) {38const largest = array[largestValueIndex];39array[largestValueIndex] = array[index];40array[index] = largest;41maxHeapify(array, largestValueIndex, heapSize);42}43}
Heap
- 完全二元樹 (complete binary tree)
- 由上至下、由左至右的順序加入節點
- max-heap: 所有父節點的值大於其子節點 (min-heap 則相反)
以上圖 max-heap 為例:
- 以陣列表示為
[100, 19, 36, 17, 3, 25, 1, 2, 7]
- 節點
i
的左子節點為2i + 1
- 節點
i
的右子節點為2i + 2
Heapify
將無序陣列轉換成 heap 的過程稱為 heapify,其流程如下:
- 由最後非葉子節點開始,對每個節點 heapify 子樹,確保每個子樹符合 heap 性質
- 以 max-heap 為例,比較父節點、左子節點、右子節點的最大值,若父節點不是最大值,交換位置並往下檢查子樹
javascript
1// create max-heap2const nums = [5, 3, 2, 10, 1, 9, 8, 6, 4, 7];34// Math.floor(nums.length / 2) - 1 is the last non-leaf node index5for (let i = Math.floor(nums.length / 2) - 1; i >= 0; i--) {6maxHeapify(nums, i, nums.length);7}89function maxHeapify(array, index, heapSize) {10const leftIndex = 2 * index + 1;11const rightIndex = 2 * index + 2;1213let largestValueIndex = index;1415if (heapSize > leftIndex && array[largestValueIndex] < array[leftIndex]) {16largestValueIndex = leftIndex;17}1819if (heapSize > rightIndex && array[largestValueIndex] < array[rightIndex]) {20largestValueIndex = rightIndex;21}2223if (index !== largestValueIndex) {24const largest = array[largestValueIndex];25array[largestValueIndex] = array[index];26array[index] = largest;27maxHeapify(array, largestValueIndex, heapSize);28}29}
Step by step
逐步說明下方範例 loop 過程:
- 紅色表示參與比對節點
- 綠色表示實際更新節點
text
nums = [5, 3, 2, 10, 1, 9, 8, 6, 4, 7]
Step 1:
text
nums = [5, 3, 2, 10, 1, 9, 8, 6, 4, 7]i = 4parentValue = 1leftIndex = 9 (2i + 1)leftValue = 7rightIndex = 10 (2i + 2)rightValue ignored since out of boundswap 1 and 7nums = [5, 3, 2, 10, 7, 9, 8, 6, 4, 1]check subtree rooted at index 9---index 9 is a leaf node, stop
Step 2:
Rendering diagram...
text
nums = [5, 3, 2, 10, 7, 9, 8, 6, 4, 1]i = 3parentValue = 10leftIndex = 7 (2i + 1)leftValue = 8rightIndex = 8 (2i + 2)rightValue = 6no swap needed
Step 3:
Rendering diagram...
Rendering diagram...
text
nums = [5, 3, 2, 10, 7, 9, 8, 6, 4, 1]i = 2parentValue = 2leftIndex = 5 (2i + 1)leftValue = 9rightIndex = 6 (2i + 2)rightValue = 8swap left child 9 and parent 2nums = [5, 3, 9, 10, 7, 2, 8, 6, 4, 1]check subtree rooted at index 5---index 5 is a leaf node, stop
Step 4:
Rendering diagram...
Rendering diagram...
Rendering diagram...
Rendering diagram...
text
nums = [5, 3, 9, 10, 7, 2, 8, 6, 4, 1]i = 1parentValue = 3leftIndex = 3 (2i + 1)leftValue = 10rightIndex = 4 (2i + 2)rightValue = 7swap left child 10 and parent 3nums = [5, 10, 9, 3, 7, 2, 8, 6, 4, 1]check subtree rooted at index 3---i = 3parentValue = 3leftIndex = 7 (2i + 1)leftValue = 6rightIndex = 8 (2i + 2)rightValue = 4swap left child 6 and parent 3nums = [5, 10, 9, 6, 7, 2, 8, 3, 4, 1]check subtree rooted at index 7---index 7 is a leaf node, stop
Step 5:
Rendering diagram...
Rendering diagram...
Rendering diagram...
Rendering diagram...
Rendering diagram...
text
nums = [5, 10, 9, 6, 7, 2, 8, 3, 4, 1]i = 0parentValue = 5leftIndex = 1 (2i + 1)leftValue = 10rightIndex = 2 (2i + 2)rightValue = 9swap left child 10 and parent 5nums = [10, 5, 9, 6, 7, 2, 8, 3, 4, 1]check subtree rooted at index 1---i = 1parentValue = 5leftIndex = 3 (2i + 1)leftValue = 6rightIndex = 4 (2i + 2)rightValue = 7swap right child 7 and parent 5nums = [10, 7, 9, 6, 5, 2, 8, 3, 4, 1]check subtree rooted at index 4---i = 4parentValue = 5leftIndex = 9 (2i + 1)leftValue = 1rightIndex = 10 (2i + 2)rightValue ignored since out of boundno swap needed