# Lecture 07 - Heap sort > 課程內容 : 中興大學資工系 范耀中教授 (112 學年度第 2 學期) > > 其他科目內容請參見 [[Here]](https://hackmd.io/@ChenZE/By4SOO6Jyl) ## 1. Question > **Top M question :** > Given a sequence with n number, then choose the largest M number. 假設一組數列 : 100, 2, 30, 4, 22, 88, 28, 11, 19, 20, 30, 50, 5, 7, 1000,要從其中挑出最大的 5 個數字 ### 1.1 Solution (1) : unordered method 以 unordered method 的方法來說,挑選過程中不需要時刻保持長度為 m 的序列的內部數字的大小順序,具體過程如下 : * 將序列的數字依序往左放入長度為 5 的陣列中 * 陣列塞滿後,從陣列左側放入並開始比較 * 遇較大的數,向後(右)移動 * 欲較小的數,取代,且取代的數字往後繼續比較 | Step | Insert | $a_1$ | $a_3$ | $a_3$ | $a_4$ | $a_5$ | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | 1 | 100 | 100 | | 2 | 2 | 100 | 2 | | 3 | 30 | 100 | 2 | 30 | | 4 | 4 | 100 | 2 | 30 | 4 | | 5 | 22 | 100 | 2 | 30 | 4 | 22 | | 6 | 88 | 100 | **88** | 30 | 4 | 22 | | 7 | 28 | 100 | 88 | 30 | **28** | 22 | | 8 | 11 | 100 | 88 | 30 | 28 | 22 | | 9 | 19 | 100 | 88 | 30 | 28 | 22 | | 10 | 20 | 100 | 88 | 30 | 28 | 22 | | 11 | 30 | 100 | 88 | 30 | 28 | 22 | | 12 | 50 | 100 | 88 | **50** | 30 | 28 | | 13 | 5 | 100 | 88 | 50 | 30 | 28 | | 14 | 7 | 100 | 88 | 50 | 30 | 28 | | 15 | 1000 | **1000** | 100 | 88 | 50 | 30 | 因為有 n 個數字要填入,且每個數字都需要比較 m 次,因此時間複雜度為 $N \times M$ ### 1.2 Solution (2) : ordered method 另一種 ordered 的方法,在挑選過程中隨時會保持陣列中的大小順序,具體過程如下 : * 從右側填入 * 填入數字檢查 * 比右側數字大,交換 * 比右側數字小,不變 * 陣列填滿後從左側插入數字繼續做比較 | Step | Insert | $a_1$ | $a_3$ | $a_3$ | $a_4$ | $a_5$ | | :-: | :-: | :-: | :-: | :-: | :-: | :-: | | 1 | 100 | | | | | 100 | | 2 | 2 | | | | 2 | 100 | | 3 | 30 | | | 30 | 2 | 100 | | 4 | | | | **2** | **30** | 100 | | 5 | 4 | | 4 | 2 | 30 | 100 | | 6 | | | **2** | **4** | 30 | 100 | | 7 | 22 | 22 | 2 | 4 | 30 | 100 | | 8 | | **2** | **22** | 4 | 30 | 100 | | 9 | | 2 | **4** | **22** | 30 | 100 | | 10 | 88 | 88 | 4 | 22 | 30 | 100 | | 11 | | **4** | **88** | 22 | 30 | 100 | | 12 | | 4 | **22** | **8** | 30 | 100 | | 13 | | 4 | 22 | **30** | **88** | 100 | 後面依此推類,因為過程中永遠都會保持陣列中的順序,所以稱為 ordered method。Best case 的時間複雜度為 N,worse case 的時間複雜度為 N×M。 這樣的問題,其實可以用 heap sort 來完成, > Heap sort 可以說是理論上最完美的 sorting ## 2. Review : heap Heap 有 5 個主要的核心概念,以下簡述之 ### 2.1 Core concept (1) > Heap must be a complete binary tree Complete tree 的概念有二 : * 除了最後一層外,所有的 node 都必須是滿的 * 最後一層的 node 需由左至右依序填滿 ![未命名](https://hackmd.io/_uploads/rJ27_zp11e.png) ### 2.2 Core concept (2) > Parent node's values always larger than its children ![未命名](https://hackmd.io/_uploads/Syv8KG6yyx.png) ### 2.3 Core concept (3) > Heap can use an array to implement 任何的 heap 都可以用一個陣列來實作,以下圖的 complete binary tree 為例 ![image](https://hackmd.io/_uploads/Hy3KfE6y1g.png) 使用 array 實作後可得 $[-, 100, 88, 7, 87, 65, 3, 4, 2]$, 其中開頭的第一項為了計算方便,所以不填值 ### 2.3 Core concept (4) > Tree traversal can be done by simple math : > * For children of node $i$ : $2i$ or $2i+1$ > * For parent of node $i$ : $\lfloor \cfrac{i}{2} \rfloor$ 以上述的陣列與 binary complete tree 的 3 號節點(數字 7)為例,3 號節點的 children node 為 6 號與 7 號節點 $$ \begin{align} 2 \times 3 = 6\\ 2 \times 3 + 1 = 7 \end{align} $$ 3 號節點的 parent node 為 1 號節點 $$ \lfloor \frac{3}{2}\rfloor = 1 $$ ### 2.4 Core concept (5) > Two operation : insert and delete 以下圖的 binary complete tree 為例,欲在 9 號位置 insert一個 node ![image](https://hackmd.io/_uploads/rJWk_N6k1e.png) ##### Insert 通常是新增節點到最後一個位置,如下圖,新增 9 號節點後開始力爭上游往上比較,遇到較小的數字就做交換,值得沒得換為止,這個動作稱為 swim up ![image](https://hackmd.io/_uploads/S11Ld46y1x.png) ##### Delete 通常是刪除根節點,有以下幾個步驟 ![image](https://hackmd.io/_uploads/SJvyhNp1Jl.png) * 先把根節點 pop 出來 * 把最小的節點往上移動 * 第 2 層的 node 互相比較,較大的再跟 i = 1 的 node 交換 * 繼續比較,直到無法下沉為止 這個動作稱為 sink down ## 3. Complete binary tree 以 complete binary tree 來說,假設有 n 個節點,則樹的高度為 $\lfloor \log_2 N\rfloor$,且 delete 與 insert 的時間複雜度都是 $\log_2 N$,因為有 N 個 layer 需要做比較。 此外,從 delete 的過程可以發現到下沉(sink down)的順序其實就是排序大小的順序