108 年 國立政治大學資訊管理學系碩士班科技組《資料結構》
第 1 題
: In a splay tree, splaying a node means moving the node to the leaf.
登入後即可作答並保存紀錄。
核心觀念
Splay tree(伸展樹)是二元搜尋樹的一種。當某個節點被存取、插入或刪除後,會進行 splay(伸展)操作,沿著該節點到根節點的路徑旋轉,使該節點移動到:
而不是移動到葉節點(leaf)。
常見的伸展旋轉包含:
- Zig:節點的父節點就是根節點,進行一次旋轉。
- Zig-Zig:節點與父節點位於祖父節點的同一側,進行兩次同方向旋轉。
- Zig-Zag:節點與父節點位於相反側,進行兩次不同方向旋轉。
這些旋轉的共同目的,都是將指定節點提升至根節點。
解題方法
判斷敘述中的「splaying a node means」所描述的操作目標即可。
若節點目前位於樹中的內部位置,伸展操作會持續對它與父節點、祖父節點進行旋轉。例如:
第 2 題
: Multiple entries can have the same key in a map but not in a dictionary.
登入後即可作答並保存紀錄。
核心觀念
本題考查 Map 與 Dictionary 對於鍵(key)重複性的定義差異。
- Map:由多筆 entry 組成,每筆 entry 為一組 。同一個 key 可以對應多個 value,因此允許多筆 entry 擁有相同 key。
- Dictionary:通常要求每個 key 唯一。一個 key 至多對應一筆資料;若插入相同 key,通常會更新原有 value,或拒絕此次插入。
因此,兩者主要差異之一,就是是否允許重複的 key。
解題方法
直接比較題目敘述與兩種抽象資料型態的定義:
- 題目指出 Map 可以有相同 key 的多筆 entry。
- 題目指出 Dictionary 不允許相同 key。
- 這正符合一般資料結構教材對 Map 與 Dictionary 的區分。
例如:
Map 可儲存:
其中 key 101 重複,但 value 不同,這在 Map 中是允許的。
第 3 題
: Using an unsorted list to implement a map, get(k) takes time to find the entry associated with key k.
登入後即可作答並保存紀錄。
核心觀念
Map(映射)由許多鍵值對組成:
其中每個 key 對應一個 value。使用未排序串列(unsorted list)實作 Map 時,資料沒有依照 key 排列,因此執行 get(k) 必須逐一比較每個元素的 key,直到找到目標鍵 。
這本質上是線性搜尋(linear search)。
解題方法
假設 Map 中共有 筆資料:
執行 get(k) 時,最多需要比較:
若目標 key 位於最後一筆,或 Map 中根本沒有 key ,就必須檢查全部 筆資料,因此最壞情況時間複雜度為:
更精確地說:
- 最好情況:目標 key 位於第一筆,時間為 。
- 最壞情況:目標 key 位於最後一筆,或 key 不存在,時間為 。
- 平均情況:若目標位置均勻分布,平均約需檢查 筆,仍為 。
第 4 題
A hash function maps a key to an integer in a fixed interval, e.g., for a hash table associated with an Array of size .
登入後即可作答並保存紀錄。
核心觀念
雜湊函數(hash function)的作用,是將鍵值(key)映射至雜湊表中的某個位置。若雜湊表共有 個槽位(slot),通常定義為:
其中 是所有可能鍵值的集合, 是鍵值 對應的陣列索引。
因此,雜湊函數的輸出範圍必須與實際雜湊表的索引範圍相符,才能直接利用 存取陣列位置。
解題方法
題目指出:
- Array 的大小為 ;
- 雜湊函數的輸出範例卻是 。
大小為 的陣列,其合法索引為:
因此,若雜湊函數的結果要直接作為陣列索引,應定義為:
或寫成:
第 5 題
: In a hash table, collision occurs when a key is mapped to different indices.
登入後即可作答並保存紀錄。
核心觀念
雜湊表(hash table)利用雜湊函數 將鍵值 映射至表格中的索引:
其中 為雜湊表中的位置。
**碰撞(collision)**的正式定義是:
兩個不同的鍵值被雜湊函數映射到相同的索引。
若 ,但滿足:
則發生碰撞。
例如:
因為 ,但兩者都被映射至索引 ,所以產生碰撞。
解題方法
判斷題目敘述是否正確時,直接對照碰撞的定義:
- 題目敘述描述的是「一個鍵被映射到不同索引」。
- 碰撞的正確情況是「不同的鍵被映射到同一索引」。
兩者在「鍵的數量」與「索引是否相同」上都相反。
雜湊函數在相同輸入下應產生相同輸出,因此同一個鍵 應固定映射至同一個索引:
若同一個鍵在不同時間被映射至不同索引,通常代表雜湊函數不穩定、雜湊表內容或計算條件發生改變,並非碰撞的標準定義。
選項分析
本題雖未列出選項,但題目本身是一個是非判斷敘述:
第 6 題
: Double hashing handles collisions by putting the colliding items in the next closest available table cell.
登入後即可作答並保存紀錄。
核心觀念
本題考查雜湊表碰撞處理中的「Double Hashing(雙重雜湊)」與「Linear Probing(線性探測)」之區別。
雙重雜湊使用兩個雜湊函數:
其中:
- :第一次計算出的起始位置。
- :決定每次探測時的跳躍步長。
- :第 次探測。
- :雜湊表大小。
因此,雙重雜湊發生碰撞後,不是固定檢查下一個相鄰位置,而是依照第二個雜湊函數所決定的步長跳躍探測。
解題方法
判斷題目敘述所描述的探測方式:
Double hashing handles collisions by putting the colliding items in the next closest available table cell.
其中「放入下一個最近且可用的表格位置」表示從碰撞位置開始,依序檢查下一格、下下格,直到找到空位。這正是線性探測的作法:
雙重雜湊則採用:
第 7 題
: A postorder traversal of a binary search tree visits the keys in increasing order.
登入後即可作答並保存紀錄。
核心觀念
二元搜尋樹(Binary Search Tree, BST)遵守:
- 左子樹所有鍵值 根節點鍵值
- 右子樹所有鍵值 根節點鍵值
三種深度優先走訪順序為:
- Preorder:根、左、右
- Inorder:左、根、右
- Postorder:左、右、根
其中,BST 的鍵值必須透過 inorder traversal 才能保證以遞增順序走訪。
解題方法
題目宣稱「BST 的 postorder traversal 會以遞增順序走訪鍵值」,只要依照 postorder 定義建立反例即可判斷。
考慮以下 BST:
2
/ \
1 3
其 postorder 順序為:
- 走訪左子樹:
- 走訪右子樹:
- 最後走訪根節點:
因此走訪結果為:
此序列並非遞增,因為 。
根本原因是 postorder 將根節點放在最後;但在一般 BST 中,根節點不一定是最大鍵值,右子樹中的節點可能比根節點大。
正確觀念對照
第 8 題
: A preorder traversal of a binary search tree visits the keys in decreasing order.
登入後即可作答並保存紀錄。
核心觀念
本題考查二元搜尋樹(Binary Search Tree, BST)的性質,以及前序走訪(preorder traversal)的順序。
- BST 對任一節點 而言:
- 左子樹所有鍵值小於 ;
- 右子樹所有鍵值大於 。
- 前序走訪順序為:
因此,前序走訪的第一個鍵值一定是樹根。
解題方法
題目敘述:
A preorder traversal of a binary search tree visits the keys in decreasing order.
意思是:某棵二元搜尋樹的前序走訪結果會依鍵值遞減排列。
設樹根鍵值為 。由於前序走訪首先拜訪樹根,後續所有節點都必須小於 ,才能維持遞減順序。
若樹根存在右子樹,則右子樹中的每個鍵值都大於 。前序走訪在拜訪完左子樹後會拜訪右子樹,因此右子樹節點會出現在樹根之後,形成:
這與整體遞減順序矛盾。因此,樹根不能有右子樹。
同樣地,對樹中的每一個節點套用相同推理,可知任何節點都不能有右子樹。這棵 BST 必須呈現只含左子節點的單鏈結構:
第 9 題
: Removing a key takes time for a binary search tree that has nodes with height .
登入後即可作答並保存紀錄。
核心觀念
本題考查二元搜尋樹(Binary Search Tree, BST)的刪除操作時間複雜度。
BST 的特性為:
- 每個節點左子樹的鍵值小於該節點。
- 每個節點右子樹的鍵值大於該節點。
- 搜尋、插入、刪除通常只需沿著「根到某一葉節點」的路徑進行。
- 若樹高為 ,根到最深節點最多經過 層,因此相關操作的時間複雜度通常為 。
解題方法
刪除 BST 中的鍵值,主要分為三種情況:
-
刪除葉節點
直接將該節點移除即可。尋找該節點最多需走過樹高 ,因此時間為:
-
刪除只有一個子節點的節點
將該節點的子節點接到其父節點下方。尋找節點與重新連結皆不超過樹高,因此時間為:
-
刪除具有兩個子節點的節點
通常尋找其中序後繼(右子樹中的最小節點)或中序前驅(左子樹中的最大節點),再進行節點替換與刪除。
搜尋與調整仍然只會沿著樹中的路徑進行,因此時間為:
所以,BST 刪除一個鍵值的精確複雜度應寫為:
與 的關係
一棵含有 個節點的樹,其高度最多為:
因此:
也就是說,若刪除操作為 ,則它也必然屬於 。
在最壞情況下,BST 退化成鏈結串列:
第 10 題
: An AVL tree is a binary search tree where for every internal node, the heights of its children are at the most one difference.
登入後即可作答並保存紀錄。
核心觀念
AVL tree(AVL 樹)是一種自我平衡的二元搜尋樹,必須同時符合:
- 二元搜尋樹性質:對任一節點,其左子樹所有鍵值小於該節點,右子樹所有鍵值大於該節點。
- 高度平衡性質:對每個節點 ,其左、右子樹高度差的絕對值不得超過 。
平衡因子定義為:
AVL 樹要求:
等價地表示為:
其中 表示子樹高度。若某一側沒有子樹,必須依題目或課本慣例設定其高度;常見設定為空樹高度 、葉節點高度 。
解題方法
題幹敘述:
An AVL tree is a binary search tree where for every internal node, the heights of its children are at the most one difference.
可分成兩個條件判斷:
- 「a binary search tree」:表示 AVL 樹必須是二元搜尋樹。
- 「for every internal node, the heights of its children are at the most one difference」:表示
第 11 題
: Hashing is efficient when the load factor (the number of stored elements / the size of the Array) is close to 100%.
登入後即可作答並保存紀錄。
核心觀念
本題考查雜湊(Hashing)的負載因子(load factor)與查詢效率之關係。
負載因子定義為:
其中:
- :目前儲存的元素數量
- :雜湊表陣列的大小
- :負載因子
「接近 100%」表示 接近 ,也就是陣列中的位置幾乎都已被使用。
解題方法
判斷此敘述是否正確,須觀察負載因子升高時碰撞(collision)的情況。
當 接近 時,可使用的空間很少,新的元素較容易與既有元素發生碰撞,導致:
- 插入時需要尋找更多位置;
- 查詢時需要檢查更多候選位置;
- 刪除與搜尋的平均成本上升;
- 嚴重時,時間複雜度會由平均 退化為 。
以開放定址法(open addressing)為例,所有元素都直接放在陣列中。當 越接近 ,空位越少,線性探測、二次探測等方法需要探查的次數越多,因此效率會明顯下降。當 時,表格已完全沒有空位,無法再直接插入新元素。
第 12 題
: A skip list is a series of lists where each list is a subsequence of the previous one.
登入後即可作答並保存紀錄。
核心觀念
本題考查 Skip List(跳躍串列) 的結構定義。
Skip List 由多層已排序串列組成,通常包含:
- 最底層串列:存放所有資料元素。
- 上層串列:從下一層挑選部分元素形成,作為快速跳躍與搜尋的索引。
- 每一層皆維持與底層相同的排序順序。
因此,若由底層往上觀察,每一層都是下一層的子序列(subsequence)。題目所述:
A skip list is a series of lists where each list is a subsequence of the previous one.
其意義是:Skip List 是一系列串列,且每一個串列都是前一個串列的子序列。
解題方法
判斷此敘述是否符合 Skip List 的正式定義即可。
設最底層串列為
上方各層可能為:
第 13 題
: In a skip list with entries, the expected search, insertion and deletion time is .
登入後即可作答並保存紀錄。
核心觀念
Skip list(跳躍表)以多層有序鏈結串列組成:
- 第 層包含所有 筆資料。
- 上層以機率 隨機抽取部分節點,形成較稀疏的索引層。
- 搜尋時由最高層開始,向右前進;若再向右會超過目標值,便下降一層。
標準隨機 Skip list 的高度期望為 ,因此搜尋、插入與刪除的期望時間皆為:
而非 。
解題方法
判斷此敘述的關鍵,在於區分「期望時間」與「最壞情況時間」。
在標準 Skip list 中,假設每個節點晉升至上一層的機率為固定常數 ,則第 層的節點數期望約為:
當上層節點數降至常數級時,有:
因此:
搜尋過程中,每一層平均只需前進常數次,總共經過 層,所以:
插入時,先搜尋新節點應插入的位置,再依隨機結果將節點加入若干層,因此:
刪除時,同樣先找到目標節點,再從其出現的各層移除。節點出現的層數期望為常數,且尋找位置需 ,因此:
第 14 題
: Two edges in a graph are parallel if they have the same end vertices.
登入後即可作答並保存紀錄。
核心觀念
在圖論中,若兩條邊連接相同的端點,則稱這兩條邊為平行邊(parallel edges)。
對無向圖而言,邊 與 若皆連接頂點 、,可表示為:
即使兩條邊是不同的邊,只要它們的端點相同,就屬於平行邊。含有平行邊的圖通常稱為多重圖(multigraph)。
解題方法
題目給出的敘述是:
Two edges in a graph are parallel if they have the same end vertices.
將其翻譯為中文:
圖中的兩條邊若具有相同的端點,則稱為平行邊。
這正是平行邊的定義,因此敘述成立。
對有向圖而言,還需考慮方向;兩條有向邊必須具有相同的起點與相同的終點,例如:
第 15 題
: Two vertices in a graph are adjacent if there exists an edge having these two vertices as its end vertices.
登入後即可作答並保存紀錄。
核心觀念
本題考查圖論中「相鄰頂點(adjacent vertices)」的定義。
在無向圖 中,若存在一條邊 ,其兩個端點正好是頂點 與 ,則稱 與 相鄰,記作:
形式化表示為:
其中:
- :頂點集合
- :邊集合
- :圖中的兩個頂點
- :連接 與 的邊
解題方法
直接依照相鄰頂點的定義判斷:
題目敘述為:
若存在一條邊,其兩個端點是這兩個頂點,則這兩個頂點相鄰。
第 16 題
: The sum of the degrees of all vertices is equal to the number of edges in an undirected graph.
登入後即可作答並保存紀錄。
核心觀念
無向圖的「頂點度數」是與該頂點相接的邊數。無向圖中的每一條邊都會連接兩個端點,因此會對兩個頂點各貢獻 度。
因此,無向圖的握手定理為:
其中:
- :頂點集合
- :邊集合
- :頂點 的度數
解題方法
逐一計算每條邊對所有頂點度數總和的貢獻:
- 任取一條無向邊 。
- 該邊使頂點 的度數增加 。
- 同時使頂點 的度數增加 。
- 因此,一條邊總共使度數總和增加 。
若圖中共有 條邊,則:
題目敘述聲稱度數總和等於邊數 ,少了倍數 ,所以敘述錯誤。
例如,若無向圖只有一條邊連接兩個頂點,則兩個頂點的度數皆為 :
第 17 題
: The number of edges in a undirected graph is greater than ( is the number of vertices in the graph).
登入後即可作答並保存紀錄。
核心觀念
在含有 個頂點的「簡單無向圖」中,任意兩個不同頂點之間最多只能有一條邊,且不允許自迴圈。
每條邊對應一組不同頂點,因此最多的邊數等於從 個頂點中選出 個:
此數值是簡單無向圖的最大邊數。
解題方法
要判斷敘述是否正確,只需比較無向圖的最大可能邊數與題目所給的數值。
對每一對不同頂點建立一條邊,可得到完全圖 。其邊數為:
因此,任何含有 個頂點的簡單無向圖皆滿足:
第 18 題
: Checking whether two vertices are adjacent can be done in time in an edge-list graph.
登入後即可作答並保存紀錄。
核心觀念
本題考查圖形資料結構中,判斷兩個頂點是否相鄰所需的時間複雜度。
若圖以 edge list(邊串列) 儲存,資料內容通常是:
其中每一筆代表一條邊, 為圖中的邊數。判斷頂點 與 是否相鄰,必須確認邊 或 是否存在於串列中。
解題方法
逐一檢查每條邊:
- 讀取一筆邊 。
- 判斷是否符合 ,或無向圖中的 。
- 若找到則表示兩頂點相鄰;若檢查完所有邊仍未找到,則表示不相鄰。
最壞情況下,目標邊位於串列最後,或根本不存在,因此需要檢查全部 條邊:
若以漸進緊確界表示,線性搜尋的最壞情況為:
因此,單純使用 edge list 時,無法保證以 時間完成相鄰性判斷。
選項分析
題目敘述:
第 19 題
: Removing a vertex in an adjacency-matrix graph takes time ( is the number of vertices in the graph).
登入後即可作答並保存紀錄。
核心觀念
鄰接矩陣以二維陣列表示圖。若圖有 個頂點,矩陣大小為 ,其中:
- 表示頂點 與頂點 之間有邊;
- 表示兩者之間沒有邊。
刪除一個頂點時,不只要刪除該頂點所對應的資料,還必須移除:
- 該頂點對應的整列;
- 該頂點對應的整欄。
這是因為該頂點與其他所有頂點的邊資訊,分別儲存在矩陣的一整列與一整欄中。
解題方法
假設要刪除頂點 :
- 刪除第 列,需要處理約 個元素;
- 刪除第 欄,也需要處理約 個元素。
因此總處理量為:
忽略常數後,時間複雜度為:
若要求刪除後仍維持緊密的 鄰接矩陣,還可能需要搬移其他列與欄的資料,但其複雜度至少不是 ,通常仍以 的資料搬移方式實作;在常見的分析中,刪除頂點所需檢查或清除其相關列、欄至少為 。
第 20 題
: A spanning tree of a graph is a tree that covers all connected vertices in a graph.
登入後即可作答並保存紀錄。
核心觀念
本題考查圖論中的「生成樹(spanning tree)」定義。
對一個連通圖 而言,生成樹 必須同時符合:
- 包含原圖 的所有頂點:
- 是樹,因此必須連通且不含環。
- 若圖中共有 個頂點,生成樹必定恰有:
條邊。
因此,生成樹可以視為「保留所有頂點,但刪除部分邊,使圖成為樹」的結果。
解題方法
題幹指出:
A spanning tree of a graph is a tree that covers all connected vertices in a graph.
其中 spanning 的意義是「涵蓋整個圖的頂點」,tree 的意義是「連通且無環」。所以生成樹就是涵蓋圖中所有頂點的樹。
若原圖有 個頂點,生成樹需滿足:
第 1.1 題5 分
Represent the expression using a binary tree. (An internal node stores an operator, e.g., *, +, and an external node stores a value, e.g., 3, 5.)
登入後即可作答並保存紀錄。
核心觀念
本題考查:
- 運算子的優先順序與結合律。
- 算術運算式轉換為二元樹。
- 二元樹的表示方式:
- 內部節點儲存運算子。
- 外部節點(葉節點)儲存運算元或數值。
- 關係運算子 的優先順序低於算術運算子,因此整個運算式的根節點為 。
算術運算子的優先順序為:
同一層級的 採由左至右結合。因此:
以及:
解題方法
原式為:
依照優先順序補上完整括號:
改以二元運算子表示為:
因此,根節點是關係運算子 :
- 左子樹表示 。
- 右子樹表示 。
二元樹表示
>
/ \
- -
/ \ / \
+ 2 / *
/ \ / \ / \
2 / / 7 +
/ \ / \ / \
* 3 9 3 2 3
/ \
8 6
第 1.2 題8 分
Complete the following pseudo code to evaluate such kind of an expression.
Algorithm: evaluateExpression(T, v)
Input: A binary tree T and a node v in T
Output: the value of v
登入後即可作答並保存紀錄。
核心觀念
題目考的是「運算式二元樹(expression tree)」的遞迴求值。
在運算式二元樹中:
- 葉節點儲存運算元,例如數字 、。
- 非葉節點儲存二元運算子,例如 、、、。
- 左子樹代表運算子的左運算元,右子樹代表右運算元。
因此,節點 所代表的運算式值可由下列遞迴定義求得:
求值順序是後序走訪(postorder traversal):先計算左子樹,再計算右子樹,最後執行目前節點的運算子。
解題方法
先判斷目前節點是否為葉節點:
- 若是葉節點,直接回傳其運算元。
- 若不是葉節點,遞迴計算左子樹與右子樹。
- 依目前節點的運算子,合併兩個子樹的結果。
完整虛擬碼
以下假設:
v.key儲存運算元或運算子。v.left與v.right分別為左、右子節點。- 運算子只有二元運算,例如
+、-、*、/。
Algorithm: evaluateExpression(T, v)
Input: A binary tree T and a node v in T
Output: The value of the expression rooted at v
if v.left == NULL and v.right == NULL then
return v.key
leftValue = evaluateExpression(T, v.left)
rightValue = evaluateExpression(T, v.right)
if v.key == '+' then
return leftValue + rightValue
else if v.key == '-' then
return leftValue - rightValue
else if v.key == '*' then
return leftValue * rightValue
else if v.key == '/' then
return leftValue / rightValue
第 1.3 題7 分
Complete the following pseudo code that prints a binary tree expression with correct parentheses, i.e., .
Algorithm: printExpression(T, v)
Input: A binary tree T and a node v in T
登入後即可作答並保存紀錄。
核心觀念
本題考查以二元樹表示算術/比較運算式,以及遞迴走訪二元樹。
- 葉節點代表運算元,例如數字 。
- 內部節點代表二元運算子,例如 。
- 每個內部節點的左子樹是左運算式,右子樹是右運算式。
- 為確保運算優先順序與結合方式完全正確,每個二元運算都加上一對括號。
若內部節點 的元素為運算子,則其表示式為:
解題方法
採用後序結構的遞迴組合方式:
- 若 是葉節點,直接輸出其內容。
- 若 是內部節點:
- 先輸出左括號
(。 - 遞迴輸出左子樹。
- 輸出目前節點的運算子。
- 遞迴輸出右子樹。
- 最後輸出右括號
)。
- 先輸出左括號
如此可保證每個內部節點都形成:
(左運算式 運算子 右運算式)
完整虛擬碼
Algorithm: printExpression(T, v)
Input: A binary tree T and a node v in T
if v is an external node of T then
print(element(v))
else
print("(")
printExpression(T, left(v))
print(element(v))
printExpression(T, right(v))
print(")")
其中:
external node表示葉節點。left(v)取得 的左子節點。right(v)取得 的右子節點。
第 2.1 題10 分
Describe the bottom-up construction step-by-step and show how the values of an array updated. Hint: at each iteration, add half of new values to merge heaps
Input: an array to build a max-heap of {13, 2, 16, 21, 15, 79, 32, 24, 20, 14, 7, 82, 51, 43, 55, 59, 8, 1} (the value of the parent node is larger than the value of its child node).
登入後即可作答並保存紀錄。
核心觀念
本題考查最大堆積(max-heap)的自底向上建構法(bottom-up heap construction)。
最大堆積必須同時滿足:
- 完全二元樹:以陣列儲存時,節點位置固定。
- 堆積順序:每個父節點值都不小於其子節點值。
採用 1-based 陣列索引時:
對含有 個元素的陣列,葉節點為第 至第 個位置,因此不必再調整。內部節點為:
自底向上依序對節點 執行下濾(sift-down)。每次都是將一個新根節點加入兩個已經建好的子堆,並向下交換至正確位置。
解題方法與逐步建構
原始陣列為:
第 1 步:處理節點
節點 的值為 ,子節點為:
- 左子節點:
- 沒有右子節點
因為 ,不需交換。
第 2 步:處理節點
節點 的值為 ,子節點為 與 。
選擇較大的子節點 ,交換:
陣列更新為:
第 3 步:處理節點
節點 的值為 ,子節點為 與 。
選擇較大的子節點 ,交換:
陣列更新為:
第 4 步:處理節點
節點 的值為 ,子節點為 與 。
選擇較大的子節點 ,交換:
陣列更新為:
第 5 步:處理節點
節點 的值為 ,子節點為 與 。
因為:
不需交換。
第 6 步:處理節點
節點 的值為 ,子節點為 與 。
選擇較大的子節點 ,交換:
此時 移至位置 ,其子節點為 與 。因為 ,再交換:
陣列更新為:
第 2.2 題10 分
Apply remove() to the heap twice and show the result step by step.
Input: Use an array to build a max-heap of {13, 2, 16, 21, 15, 79, 32, 24, 20, 14, 7, 82, 51, 43, 55, 59, 8, 1} (the value of the parent node is larger than the value of its child node).
登入後即可作答並保存紀錄。
核心觀念
本題考查兩個操作:
- 使用 Bottom-up Build-Max-Heap 將陣列建成最大堆積(max-heap)。
- 對最大堆積連續執行兩次
remove(),每次刪除根節點的最大值。
採用 1-based index 表示陣列:
- 父節點索引:
- 左子節點索引:
- 右子節點索引:
最大堆積必須滿足:
remove() 的流程為:
- 移除根節點。
- 將最後一個元素移到根節點。
- 由根向下與較大的子節點交換,直到恢復最大堆積性質。
解題方法:建立最大堆積
原始陣列為:
由最後一個非葉節點 開始,依序向前進行下濾(sift-down)。
主要交換結果如下:
- : 與子節點 交換。
- : 與較大子節點 交換。
- : 與子節點 交換。
- : 與 交換,接著 與 交換。
- : 與 交換,接著與 交換。
- : 依序與 、、 交換。
- : 依序與 、、 交換。
建成的最大堆積為:
其樹狀結構為:
82
/ \
59 79
/ \ / \
24 15 51 55
/ \ / \ / \ / \
21 20 14 7 16 13 43 32
/ \ /
2 8 1
第一次 remove()
原本根節點為最大值 ,將最後元素 移至根:
向下調整:
- 與較大的子節點 交換:
第 3.1 題10 分
The first idea is using a loop and iteratively computing average. Complete the following pseudo code and analyze its time complexity.
Algorithm IterativeAverage (A, i, j):
Input: an array A and starting index i and end index j
Output: The average of (j-i+1) integers in A (starting from index i up to index j (included))
登入後即可作答並保存紀錄。
核心觀念
本題考查:
- 陣列區間的平均值計算。
- 迭代式迴圈設計。
- 迴圈次數與時間複雜度分析。
- 累加器(accumulator)的使用方式。
從索引 到 ,包含頭尾共有:
個整數。因此平均值為:
解題時先以變數 sum 累加區間內所有元素,迴圈結束後再除以元素個數。
解題方法
設:
sum:目前累加總和,初始值為 。k:目前處理到的索引,從 走到 。count:元素個數,等於 。
完成後的虛擬碼如下:
Algorithm IterativeAverage (A, i, j):
Input: an array A and starting index i and end index j
Output: the average of (j-i+1) integers in A
sum ← 0
for k ← i to j do
sum ← sum + A[k]
return sum / (j - i + 1)
正確性說明
迴圈執行到索引 時,sum 所代表的值為:
因此迴圈結束於 時:
再除以區間內的元素數量 ,即可得到正確平均值:
第 3.2 題10 分
Similar to mergesort, we can also apply divide and conquer to find the average of n elements. The idea is to divide n elements to two parts, recursively find the average of the first half of A and the other of the second half of A, and compute the average based on these two parts. This kind of algorithm is called binary recursion algorithm, since we use two recursive calls to solve the problem. Complete the pseudo code, write its time complexity in a recursive equation, and deduct its O time complexity.
Algorithm MergeAverage (A, i, j):
Input: an array A and starting index i and end index j
Output: The average of (j-i+1) integers in A (starting from index i up to index j (included))
登入後即可作答並保存紀錄。
核心觀念
本題考查:
- Divide and Conquer(分治法)。
- Binary Recursion(二元遞迴):每次問題分成兩個子問題。
- 平均數的加權合併。
- 遞迴時間方程式與 Master Theorem。
若左半部有 個元素、平均為 ;右半部有 個元素、平均為 ,總平均不是兩個平均數直接相加再除以二,而是:
由於陣列索引範圍為 到 ,元素個數為:
解題方法
將區間 分成左右兩半,令:
則:
- 左半部索引為 到 ,元素個數為 。
- 右半部索引為 到 ,元素個數為 。
遞迴取得兩半的平均數後,再依照各自元素數量加權合併。
完整虛擬碼
Algorithm MergeAverage(A, i, j):
Input: an array A and starting index i and end index j
Output: The average of A[i], A[i+1], ..., A[j]
if i == j then
return A[i]
m ← floor((i + j) / 2)
leftAverage ← MergeAverage(A, i, m)
rightAverage ← MergeAverage(A, m + 1, j)
leftCount ← m - i + 1
rightCount ← j - m
return (leftCount × leftAverage + rightCount × rightAverage)
/ (leftCount + rightCount)
基底條件
當 時,區間內只有一個元素,因此平均數就是該元素本身:
遞迴合併
左半部平均為 leftAverage,右半部平均為 rightAverage,所以整體平均為:
程式中的分母也可寫成:
時間複雜度推導
設 表示處理 個元素所需的時間。
每次遞迴會:
- 將問題分成兩個約為 的子問題。
- 執行常數次的索引計算、乘法、加法與除法。
因此遞迴時間方程式為:
當 不是 的次方時,嚴格寫法為: