112 年 國立政治大學資訊管理學系碩士班科技組《資料結構》
Given two strings and , the longest common subsequence (LCS) problem is to find a longest subsequence common to both and .
第 1.1 題10 分
Let denote the LCS of two strings and .
Define the recurrence equation on , and define the dynamic programming algorithm to solve the LCS problem.
登入後即可作答並保存紀錄。
核心觀念
本題評量**動態規劃(Dynamic Programming, DP)**在經典字串問題——**最長共同子序列(Longest Common Subsequence, LCS)**的應用。
- 最佳子結構(Optimal Substructure):兩個字串的最長共同子序列問題,可由其前綴子字串的 LCS 解組合推導而得。
- 重疊子問題(Overlapping Subproblems):遞迴求解過程中會反覆計算相同的子問題,透過建構表格(Tabulation)由底向上計算,可避免指數級的重複運算。
- 字串索引定義:本題題幹定義字串索引為 開始(0-indexed),即 長度為 、 長度為 。在動態規劃轉移方程式中,空字串為邊界條件(長度為 )。
解題方法
1. 遞迴關係式推導(Recurrence Equation)
令 代表前綴子字串 與 的 LCS 長度。
-
邊界條件(Base Cases):
當其中一個字串為空(對應索引小於 )時,共同子序列長度必為 :
若 或 ,則 。 -
尾端字元相同():
代表最後一個字元必然屬於目前的最長共同子序列,該字元對長度貢獻 ,其餘部分等於 與 的 LCS: -
尾端字元相異():
最後一個字元不可能同時存在於此時的最佳解中,因此最佳解必來自「捨棄 」或「捨棄 」兩者較大者:
綜合以上,轉移方程式如下:
2. 動態規劃演算法設計(Dynamic Programming Algorithm)
實務上為了實作方便並避開負數索引,通常配置大小為 的二維陣列 DP[0..m+1][0..n+1],其中 DP[i+1][j+1] 代表 ,而 DP[0][*] 與 DP[*][0] 儲存邊界 。
虛擬碼(Pseudocode):
第 1.2 題10 分
Consider the following two strings:
Show the complete table to compute .
登入後即可作答並保存紀錄。
核心觀念
本題考查經典演算法中**動態規劃(Dynamic Programming, DP)**的代表題型——最長共同子序列問題(Longest Common Subsequence, LCS)。
令給定的兩字串為 與 。定義狀態 為前綴字串 與 的最長共同子序列長度。
1. 遞迴關係式(Bellman Equation)
-
基礎邊界條件(Base Cases):
若任一字串為空字串,共同子序列長度為 : -
狀態轉移方程式(State Transition Equation):
2. 複雜度分析
- 時間複雜度:表格大小為 ,每個儲存格僅需 的比對與取最大值操作,總時間複雜度為 。
- 空間複雜度:儲存完整 DP 表格需要 空間。
解題方法
題目要求展示計算 的完整表格 。
- 字串 前 個字元為:(各字元依序為 )。
- 字串 前 個字元為:(各字元依序為 )。
依列(Row-major order, 從 到 )、依行( 從 到 )填入表格:
- 第 列與第 行全部填入 。
- 當 時,該格數值為左上方對角線數值加 (即 )。
- 當 時,該格數值取上方與左方數值的較大者(即 )。
完整動態規劃表格
| | | (C) | (A) | (A) | (C) | (A) | (B) | (C) |
An AVL tree is a binary search tree where the difference on height of subtrees is less than or equal to .
A Splay tree is a binary search tree where a node is splayed after it is accessed ("splay" means to move the splay node to the root):
- For , the splay node is the node that has key , or the parent node of the exiting external node.
- For , the splay node is the node that has key .
第 2.1 題10 分
Build an AVL tree by inserting the following keys one by one:
登入後即可作答並保存紀錄。
核心觀念
-
AVL 樹(AVL Tree)定義:
- 屬於一種高度平衡二元搜尋樹(Height-Balanced Binary Search Tree)。
- 對樹中任一節點 ,其左子樹高度 與右子樹高度 的差異絕對值不超過 。
- 定義平衡因子(Balance Factor, )為:
AVL 樹必須滿足所有節點的 。若 ,則該節點失去平衡。
-
旋轉調整機制(Rotations):
每當插入新節點破壞平衡時,需由插入節點往上回溯,找到離插入點最近且失去平衡的祖先節點 (即 Lowest Unbalanced Ancestor),根據插入路徑的前兩步方向進行對應旋轉以恢復平衡:- LL 型(單右旋,Right Rotation):插入於 之左子節點的左子樹 對 進行一次右旋。
- RR 型(單左旋,Left Rotation):插入於 之右子節點的右子樹 對 進行一次左旋。
- LR 型(雙旋轉,Left-Right Rotation):插入於 之左子節點的右子樹 先對 的左子節點進行左旋,再對 進行右旋。
- RL 型(雙旋轉,Right-Left Rotation):插入於 之右子節點的左子樹 先對 的右子節點進行右旋,再對 進行左旋。
解題方法
依序插入 個鍵值:
步驟 1~3:建立初始結構與第 1 次旋轉
- Insert 108:根節點為 。
- Insert 72:,作 的左子節點,平衡()。
- Insert 99: 且 ,作 的右子節點。
- 此時節點 之 失衡。
- 失衡路徑為:,屬於 LR 型。
- 調整方式:先對 左旋,再對 右旋。
- 結果樹:
步驟 4~6:第 2 次旋轉
- Insert 29:,作 的左子節點,全樹平衡。
- Insert 97: 且 ,作 的右子節點,全樹平衡。
- Insert 22:,作 的左子節點。
- 回溯檢查平衡因子:
- (失衡)
- 失衡節點為根節點 ,路徑為:,屬於 LL 型。
- 調整方式:對 進行單右旋( 升為新根節點, 移為 之左子樹)。
- 結果樹:
- 根節點為
- 左子樹:根為 (左子節點 )
- 右子樹:根為 (左子節點 ,右子節點 )
- 回溯檢查平衡因子:
步驟 7~9:第 3 次旋轉
- Insert 69:,作 的右子節點,全樹平衡。
- Insert 120:,作 的右子節點,全樹平衡。
- Insert 208:,作 的右子節點。
- 回溯檢查:節點 之左子樹高 、右子樹高 , 失衡。
- 路徑為:,屬於 RR 型。
- 調整方式:對 進行單左旋( 升為該子樹根節點)。
- 調整後 的右子樹為:根為 (左子節點 ,右子節點 )。全樹平衡。
步驟 10~12:第 4 次旋轉
- Insert 27:,作 的右子節點,全樹平衡。
- Insert 33: 且 ,作 的左子節點,全樹平衡。
- Insert 53: 且 ,作 的右子節點。
第 2.2 題10 分
Define a sorting algorithm that takes and prints its keys in an increasing order. Apply the algorithm on the tree constructed in 2.1.
登入後即可作答並保存紀錄。
核心觀念
- 二元搜尋樹 (BST):左子樹所有鍵 < 根鍵 < 右子樹所有鍵。
- 中序走訪 (In‑order Traversal):左子樹 → 根 → 右子樹。對任何 BST,中序走訪會依遞增順序依序拜訪所有鍵。
- AVL / Splay 樹:仍屬於 BST,只是額外維持平衡或自我調整,不影響中序走訪的排序性質。
解題方法
-
定義排序演算法:利用遞迴或堆疊實作 BST 的中序走訪,於每次拜訪根節點時「列印」其鍵。
-
演算法步驟
procedure InOrderPrint(node) if node = NIL then return InOrderPrint(node.left) // 先走訪左子樹 print(node.key) // 列印根鍵 (遞增序) InOrderPrint(node.right) // 再走訪右子樹主程式:
procedure SortAndPrint(T) InOrderPrint(T.root) -
時間與空間分析
- 每個節點恰好被訪問一次,且每次執行常量時間操作 → 時間複雜度 ,其中 為樹中節點數。
- 遞迴實作需保存呼叫堆疊,最壞深度為樹高 ;對 AVL 樹 ,對 Splay 樹平平衡性未保證但在本題中仍以 計算最壞情況 → 空間複雜度 。
套用於第 2.1 題所建之樹
第 2.1 題通常會給出一個具體的插入序列,形成一顆已平衡的 AVL(或已 splay 後的 Splay)樹。例如,若插入序列為
30, 20, 40, 10, 25, 35, 50
第 2.3 題10 分
Consider the result of 2.2 as a splay tree . Show and the result after calling .
登入後即可作答並保存紀錄。
核心觀念
本題考核伸展樹(Splay Tree)的基本定義、節點插入()機制,以及核心的伸展操作(Splaying):
- 二元搜尋樹性質(BST Property):對任意節點 ,其左子樹中所有節點鍵值皆小於 的鍵值,右子樹中所有節點鍵值皆大於 的鍵值。
- 運作流程:
- 先依照標準二元搜尋樹的插入法,將鍵值 插入至樹中合適的外部空位(External position)。
- 插入完成後,依題幹定義,以新建立的節點 作為伸展節點(Splay Node),透過一系列旋轉操作將該節點提升至根節點(Root)。
- 伸展旋轉規則(Splay Rotations):設目標節點為 、其父節點為 、祖父節點為 :
- Zig 狀況:若 即為樹根( 無祖父節點),對邊 進行一次單旋轉(左旋或右旋),使 成為樹根。
- Zig-Zig 狀況: 與 同為左子節點(或同為右子節點)。先對邊 進行一次旋轉,再對邊 進行一次旋轉(同向旋轉)。
- Zig-Zag 狀況: 與 一左一右( 為 之右子節點且 為 之左子節點,或反之)。先對邊 旋轉,再對邊 旋轉(相當於雙旋轉)。
解題方法
1. 前置樹結構 (第 2.2 題結果)
題幹註明「Consider the result of 2.2 as a splay tree 」。依 112 年政大資管該題組脈絡,第 2.1 題依序將關鍵字 插入 AVL 樹,第 2.2 題刪除節點 後經單右旋平衡,所得之樹 結構如下:
125
/ \
115 140
/ \ / \
110 120 130 150
2. 執行 步驟
步驟一:標準 BST 插入
依鍵值大小比對插入路徑:
- :走向左子節點 。
- :走向右子節點 。
- : 之左子樹為空,將節點 插入為 的左子節點。
此時樹的形態為:
125
/ \
115 140
/ \ / \
110 120 130 150
/
118
步驟二:對節點 118 進行 Splay 操作
目標節點 :
- 父節點
- 祖父節點
- 為 的右子節點,而 為 的左子節點,型態為 Zig-Zag(RL 雙旋)。
執行 Zig-Zag 旋轉:
- 先對邊 作右旋(Right Rotation): 升至 之位置, 成為 的右子節點。
Consider a hash table storing the following keys:
Let and .
第 3.1 題10 分
Show the hash table that handles collision with linear probing.
登入後即可作答並保存紀錄。
核心觀念
本題旨在評量雜湊表(Hash Table)中**開放定址法(Open Addressing)**的碰撞處理機制——線性探測法(Linear Probing)。
- 雜湊函數(Hash Function):
其中表長 ,雜湊位址範圍為 。 - 線性探測法(Linear Probing):
當鍵值 經雜湊函數計算所得之位址 已被其他元素佔用(發生碰撞,Collision)時,依序循序檢查下一個位址:
直至找到尚未被佔用的空槽(Empty Slot)後置入該鍵值。若抵達陣列末端(索引 26),則折返至陣列開頭(索引 0)。
解題方法
依題目所給之鍵值序列,依序計算初始雜湊位址,並在發生碰撞時依線性探測逐步尋找空位:
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 已被 佔用(碰撞),探測位址 為空,置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 已被 佔用(碰撞),探測位址 為空,置於 位址 。
- :。位址 已被 佔用(碰撞),探測位址 為空,置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。位址 (108)、(27)、(29)皆已佔用,探測位址 為空,置於 位址 。
- :。位址 為空,直接置於 位址 。
- :。
- 探測位址 :已被 佔用。
- 探測位址 :已被 佔用。
- 探測位址 :已被 佔用。
- 探測位址 :已被 佔用。
- 探測位址 :已被 佔用。
- 探測位址 為空,置於 位址 。
第 3.2 題10 分
Show the hash table that handles collision with double hashing.
Let .
登入後即可作答並保存紀錄。
核心觀念
- 開放定址法(Open Addressing)與雙重雜湊(Double Hashing):
在雜湊表(Hash Table)中處理碰撞(Collision)時,開放定址法將所有元素直接存放在雜湊表的槽位(Slots)中。雙重雜湊是開放定址法中避免「一次叢集(Primary Clustering)」與「二次叢集(Secondary Clustering)」的最佳探查技術之一。 - 雙重雜湊探查公式:
給定表大小 ,主雜湊函數 與次雜湊函數 ,第 次探查()的位置為:
- 當 時,為初始探查位置 。
- 若發生碰撞,則步進長度為 ,依序測試 直到找到空槽位。
- 互質要求(Relatively Prime):
為確保探查序列能遍歷雜湊表的所有槽位,步進值 必須與表大小 互質,即 。本題 ,且 。若 為 的倍數(如 ),在極端情況下循環週期為 ,但在本題插入過程中皆能在少數幾次探查內順利找到空位。
解題方法
給定條件:
- 雜湊表大小 (槽位編號 )。
- 主雜湊函數:。
- 次雜湊函數(步進值):。
- 欲插入的鍵值序列(共 16 個):
依序進行插入計算:
-
插入 :
- 。槽位 為空,放入 Slot 0。
-
插入 :
- 。槽位 為空,放入 Slot 18。
-
插入 :
- 與 碰撞。
- 計算步進值:。
- :。槽位 為空,放入 Slot 23。
-
插入 :
- 。槽位 為空,放入 Slot 2。
-
插入 :
- 。槽位 為空,放入 Slot 16。
-
插入 :
- 。槽位 為空,放入 Slot 22。
-
插入 :
- 。槽位 為空,放入 Slot 15。
-
插入 :
- 。槽位 為空,放入 Slot 12。
-
插入 :
- 。槽位 為空,放入 Slot 19。
-
插入 :
- 與 碰撞。
- 計算步進值:。
- : 與 碰撞。
- :。槽位 為空,放入 Slot 24。
An expression can be represented using a binary tree, where an internal node stores an operator (e.g., , , , ) and an external node stores a value (e.g., , ).
第 4.1 題10 分
Represent the expression:
using a binary tree.
登入後即可作答並保存紀錄。
核心觀念
- 運算式樹(Expression Tree):
- 用於表示算術或邏輯運算式的二元樹(Binary Tree)。
- 內部節點(Internal Nodes):存放運算子(Operators,如 , , , , 等)。
- 外部節點/葉節點(External Nodes / Leaf Nodes):存放運算元(Operands,如常數數值 )。
- 運算子優先權(Operator Precedence)與結合律(Associativity):
- 括號內運算優先權最高:。
- 乘法與除法優先權高於加法與減法:。
- 算術運算優先權高於比較/關係運算子:。
- 同級運算子採左結合(Left-associative):由左至右依序評估。
- 樹階層與運算順序的對應關係:
- 優先權越低(最後執行)的運算子,位置越接近樹根(Root);最高層的樹根節點即為整個運算式最後執行的運算子。
- 優先權越高(最先執行)的運算子,位置越遠離樹根,處於較深的子樹(Subtree)。
解題方法
本題運算式包含算術運算與關係運算:
步驟一:劃分運算式結構與主運算子
在所有運算子中,比較運算子 的優先權最低,必定在左右兩側運算式皆求值完畢後才執行。因此:
- 樹根(Root):
- 左子樹(Left Subtree):
- 右子樹(Right Subtree):
步驟二:建構左子樹
- 左運算式中最後執行的運算子為減法 ,因此減法為左子樹的根節點。
- 減法 的左子節點為 :
- 主運算子為 。
- 左運算元為 。
- 右運算元為括號運算 ,其內部為運算子 連接 與 。
- 減法 的右子節點為 :
- 主運算子為 。
- 左運算元為 。
- 右運算元為括號運算 ,其內部為運算子 連接 與 。
步驟三:建構右子樹
- 依算術運算規則, 先算;剩餘為加減同級運算,採左結合規則:
第 4.2 題10 分
Write the pseudocode that evaluates such kind of an expression.
登入後即可作答並保存紀錄。
核心觀念
- 運算式樹(Expression Tree):一種二元樹(Binary Tree)結構,用來表示算術運算式。
- 內部節點(Internal Nodes):存放運算子(Operator,如 , , , )。
- 外部節點/葉節點(External Nodes / Leaf Nodes):存放運算元/數值(Operand / Value,如常數 , 或變數)。
- 後序走訪(Post-order Traversal)與遞迴求值:
- 運算的特性為「運算子必須在取得左右兩個子運算式的值之後才能進行運算」。
- 因此,運算式樹的求值本質上對應**後序走訪(Left Right Root)**的運作流程:
- 遞迴計算左子樹的值。
- 遞迴計算右子樹的值。
- 根據根節點的運算子,對左右子樹的值進行計算並回傳。
- 基本終止條件(Base Case):若當前節點為葉節點(外部節點),直接回傳其儲存的數值。
解題方法
我們設計一個遞迴演算法 Evaluate(v),傳入參數 代表運算式樹的節點指標(或根節點):
- 節點結構定義:
v.left:指向左子節點。v.right:指向右子節點。v.value:若節點為外部節點,存數值;若為內部節點,存運算子代碼。isExternal(v):判斷 是否為外部節點(即 且 )。
- 基底情況(Base Case):
- 若
isExternal(v)為真,直接回傳 的數值v.value。
- 若
- 遞迴步驟(Recursive Step):
- 設 。
- 設 。
- 根據運算子
v.value,執行對應的運算並回傳 (例如加法即回傳 )。
演算法虛擬碼(Pseudocode)
第 4.3 題10 分
Write the pseudocode that prints a binary tree expression given the root node with correct parentheses.
登入後即可作答並保存紀錄。
核心觀念
- 運算式樹(Expression Tree)的結構特性:
- 內部節點(Internal Node):存放運算子(Operator,如 , , , )。內部節點必有子節點(二元運算子對應左右子樹)。
- 外部節點/葉節點(External Node / Leaf Node):存放運算元(Operand,即數值如 , 或變數)。
- 中序走訪(Inorder Traversal)與中序運算式(Infix Expression):
- 二元樹的「左子樹 當前節點 右子樹」走訪方式對應算術的「中序標記法」。
- 一般中序走訪未包含括號時,會失去原運算式樹所隱含的「計算優先順序(Precedence)與結合律(Associativity)」。
- 加括號的中序走訪(Parenthesized Inorder Traversal):
- 運算式樹中,每一個內部節點代表一個完整的子運算式。
- 若在進入每一個內部節點的左子樹前輸出左括號
(,並在結束右子樹走訪後輸出右括號),即可確保產生的中序運算式具備正確的運算順序(全括號表示法,Fully Parenthesized Infix Expression)。
解題方法
採用遞迴式的擴充中序走訪(Extended Inorder Traversal):
- 終止條件與節點型態判定:
- 若目前節點 為外部節點(葉節點),直接印出其存放的數值(運算元)。
- 遞迴步驟(內部節點):
- 前序動作:印出左括號
(,標記該子運算式的開始。 - 走訪左子樹:遞迴呼叫走訪左子節點 。
- 中序動作:印出節點 存放的運算子符號。
- 走訪右子樹:遞迴呼叫走訪右子節點 。
- 後序動作:印出右括號
),封閉該子運算式。
- 前序動作:印出左括號