跳轉至
紙質書（簡體中文版）已發行，詳情請見這裡

# 8.5 練習

## 8.5.1 知識鞏固

### 1. 數字 10 入堆積後怎樣調整

陣列 `[9, 7, 8, 3, 5]` 表示一個大頂堆積。現在將數字 10 入堆積。

1. 先把 10 新增到陣列末尾，它的父節點值是多少？
2. 從新節點開始向上堆積化，寫出每次交換後的陣列。
3. 最終的堆積頂元素是什麼？一共交換了幾次？

參考答案

1. 10 新增後的索引為 5，其父節點索引為 \(\lfloor(5-1)/2\rfloor=2\)，父節點值為 8。

2. 10 大於 8，第一次交換後為 `[9, 7, 10, 3, 5, 8]`； 10 又大於父節點 9，第二次交換後為 `[10, 7, 9, 3, 5, 8]`。 此時 10 已到達根節點，堆積化結束。

3. 最終堆積頂為 10，共交換 2 次。

### 2. 檢查小頂堆積的父子關係

陣列 `[1, 4, 3, 7, 6, 2]` 表示一棵完全二元樹。小頂堆積要求每個父節點都不大於它的孩子。 對索引 \(i\)，左、右孩子索引分別為 \(2i+1\) 和 \(2i+2\)。

1. 索引 2 的孩子索引和值分別是什麼？
2. 索引 2 處的節點值為 3，它與孩子節點之間是否違反小頂堆積規則？如果違反，應交換哪兩個元素？
3. 根據第 2 問的判斷：若違反規則，寫出交換後的陣列；若不違反，說明無須交換。最後檢查其餘父子關係。

參考答案

1. 索引 2 的左孩子索引是 5、值為 2；右孩子索引是 6，但陣列長度為 6，因此右孩子不存在。

2. 父節點值 3 大於孩子值 2，違反小頂堆積規則，應交換索引 2 和索引 5 的元素。

3. 交換後得到 `[1, 4, 2, 7, 6, 3]`。逐一檢查： `1 ≤ 4`、`1 ≤ 2`；`4 ≤ 7`、`4 ≤ 6`；`2 ≤ 3`。 所有父節點都不大於自己的孩子，因此現在滿足小頂堆積規則。

### 3. 用小頂堆積保留最大的三個數

要從資料流 `[4, 1, 7, 3, 8]` 中保留最大的 3 個數，可以維護一個大小不超過 3 的小頂堆積。

先把前 3 個數依次放入小頂堆積。堆積滿後，每讀入一個新數： 如果它大於堆積頂，就刪除堆積頂並放入新數；否則堆積保持不變。

請寫出每次讀入數字後堆積中保留的數字和堆積頂。 只需把保留的數字寫成集合，不要求寫出它們在堆積陣列中的排列。

參考答案

每次讀入數字後的結果如下：

讀入數字 | 保留的數字 | 堆積頂
--- | --- | ---
4 | `{4}` | 4
1 | `{1, 4}` | 1
7 | `{1, 4, 7}` | 1
3 | `{3, 4, 7}` | 3
8 | `{4, 7, 8}` | 4

堆積滿後，堆積頂是當前保留數字中最小的一個。只有新數字大於堆積頂時， 才用新數字替換堆積頂。最終保留的 `{4, 7, 8}` 正是最大的 3 個數。

## 8.5.2 程式設計練習

### 1. 尋找陣列中的第 k 大元素

給定整數陣列 `nums` 和整數 \(k\)，其中 \(1 \le k \le n\)，\(n\) 是陣列長度。把陣列按從大到小排列後，請返回第 \(k\) 個位置上的元素。

重複元素需要分別計數。例如，`[5, 5, 2]` 的第 2 大元素仍是 5。請使用一個大小不超過 \(k\) 的小頂堆積完成。

解題提示

1. 第 k 大元素是最大的 k 個數中最小的那個
2. 每個數先入小頂堆積，大小超過 k 時彈出最小值
3. 走訪結束時堆積中保留最大的 k 個數，堆積頂就是答案

LeetCode 題目解析

> 說明： 連結中的題解講解了快速排序和快速選擇，沒有使用堆積；本練習請按照正文 8.3 節使用大小不超過 k 的小頂堆積完成

##### 歡迎在評論區留下你的見解、問題或建議