112 年 國立臺北大學資訊工程研究所《資料結構與演算法》
第 1 題15 分
Run the Breadth-First Search (BFS) algorithm to generate a BFS searching tree which has the node s as its root. Run the algorithm step by step.
🖼️【此處有附圖,請對照原卷】
(圖片包含一個無向圖,節點有 a, b, c, d, e, s。邊有 (a,s), (b,s), (c,s), (c,b), (d,s), (d,e))
登入後即可作答並保存紀錄。
核心觀念
BFS(Breadth-First Search,廣度優先搜尋)使用佇列(Queue),從根節點 開始,依照「距離起點由近到遠」的順序拜訪節點。
BFS 的規則如下:
- 將起點 標記為已拜訪並放入佇列。
- 反覆取出佇列前端節點。
- 依序檢查其鄰接節點;尚未拜訪者標記為已拜訪、設定其父節點,並加入佇列。
- 每個節點第一次被發現時,便加入 BFS 樹,其父子邊即為樹邊。
題目圖形為無向圖,邊集合為
因此各節點的鄰接關係為:
- :
- :
- :
- :
- :
- :
以下依題目列出的鄰接順序處理。
解題方法:逐步執行 BFS
初始狀態:
- 已拜訪集合:
- 佇列:
- BFS 樹:根節點為
| 步驟 | 取出節點 | 新發現節點 | 佇列狀態 | 新增樹邊 |
|---|---|---|---|---|
| 1 | ||||
| 2 | 無 | 無 | ||
| 3 | 無; 已發現 | 無 | ||
| 4 | 無; 已發現 | 無 | ||
| 5 | ||||
| 6 | 無; 已發現 | 無 |
其中:
第 2 題10 分
Run the merge sort on the following array: (5,1,8,3,6,4,7,2) step by step.
🖼️【此處有附圖,請對照原卷】
(圖片包含一個無向圖,節點有 a, b, c, d, e, s。邊有 (a,s), (b,s), (c,s), (c,b), (d,s), (d,e))
登入後即可作答並保存紀錄。
核心觀念
Merge Sort(合併排序)採用「分割與征服」策略:
- 將陣列遞迴分割成單一元素。
- 將相鄰且已排序的子陣列兩兩合併。
- 合併時依序比較兩邊最前面的元素,較小者先放入結果。
時間複雜度為 ,額外空間複雜度為 。
題目文字要求排序陣列 ;附圖內容為無向圖,與本題 Merge Sort 無關,因此排序過程依題目文字中的陣列作答。
解題方法:分割階段
原始陣列:
第一次分割:
第二次分割:
分割至單一元素:
解題方法:合併階段
先合併相鄰的單一元素:
此時陣列分成四個已排序子陣列:
接著合併兩兩子陣列:
合併 與 :
第 3 題10 分
Give an asymptotic upper bound for the function T(n) where T(n) satisfies the recurrent equation for integer and is a constant.
🖼️【此處有附圖,請對照原卷】
(圖片包含一個無向圖,節點有 a, b, c, d, e, s。邊有 (a,s), (b,s), (c,s), (c,b), (d,s), (d,e))
登入後即可作答並保存紀錄。
核心觀念
本題考遞迴式的漸進複雜度,可使用 Master Theorem:
其中:
先計算:
因為 ,所以:
而 的成長速度明顯較快。
解題方法
比較 與 :
取適當的 即可成立,因此符合 Master Theorem 的第三種情況。若正規性條件成立:
其中 ,故:
第 4 題15 分
We have a set of n open intervals S={(aᵢ,bᵢ): i=1,..,n}. We want to choose a largest subset S' ⊆ S such that the selected intervals in S' are mutually disjoint. Please give an O(nlog n)-time algorithm to solve this problem.
🖼️【此處有附圖,請對照原卷】
(圖片包含一個無向圖,節點有 a, b, c, d, e, s。邊有 (a,s), (b,s), (c,s), (c,b), (d,s), (d,e))
登入後即可作答並保存紀錄。
核心觀念
本題考的是 區間排程(Interval Scheduling) 與 貪心演算法(Greedy Algorithm)。
對兩個開區間 與 ,若要互不相交,排序後可檢查:
由於題目使用的是「開區間」,當 時,兩區間不包含端點,仍然互不相交。
解題方法
採用「每次選擇結束時間最早的區間」:
-
將所有區間依右端點 遞增排序。
-
依序掃描排序後的區間。
-
若目前區間的左端點滿足
就選取該區間,並令
-
掃描結束後,所選區間即為最大互不相交子集合。
初始時令 。
偽程式碼:
GreedyIntervalSchedule(S):
將 S 依 b_i 遞增排序
selected = []
lastEnd = -∞
for each interval (a_i, b_i) in S:
if a_i >= lastEnd:
將 (a_i, b_i) 加入 selected
lastEnd = b_i
return selected
正確性說明
第 5 題5 分
(A) 在 C 語言中, int list[5] 和 int *plist[5] 有何不同, 要如何將 int *plist[5] 實作
為 2 維陣列?
(B) 將此 inorder statement : 轉為 postorder, 並畫出它的二元樹。
須按照以左到右讀取順序來做, 以達到單一解答。同時, 設計一個算法使用 stack 來實現上述
inorder 轉 postorder, 並且以上述 statement 說明如何使用 stack 來做轉換。
🖼️【此處有附圖,請對照原卷】
(圖片包含一個無向圖,節點有 a, b, c, d, e, s。邊有 (a,s), (b,s), (c,s), (c,b), (d,s), (d,e))
登入後即可作答並保存紀錄。
(A)int list[5] 與 int *plist[5] 的差異
核心觀念
int list[5]:宣告一個含有 5 個int的陣列。int *plist[5]:宣告一個含有 5 個「指向int的指標」之陣列。
兩者的記憶體配置不同:
int list[5];
可視為:
list[0], list[1], list[2], list[3], list[4]
每個元素直接儲存一個整數。
int *plist[5];
則是:
plist[0], plist[1], ..., plist[4]
每個元素儲存一個位址,因此每一列可以指向不同長度的整數陣列,形成不規則的二維陣列。
解題方法:逐列配置二維陣列
假設要建立 的二維陣列:
#include <stdlib.h>
int rows = 5;
int cols = n;
int *plist[5];
for (int i = 0; i < rows; i++) {
plist[i] = malloc(cols * sizeof(int));
}
之後即可使用二維陣列的方式存取:
plist[i][j] = 10;
printf("%d", plist[i][j]);
使用完畢後必須逐列釋放:
for (int i = 0; i < rows; i++) {
free(plist[i]);
}
若希望使用一整塊連續記憶體,也可以寫成:
int *data = malloc(rows * cols * sizeof(int));
int *plist[5];
for (int i = 0; i < rows; i++) {
plist[i] = data + i * cols;
}
此時 plist[i][j] 等價於:
data[i * cols + j]
複雜度與技巧
- 配置時間:;若包含初始化全部元素,則為 。
- 額外指標空間:。
int *plist[5]的每一列可獨立配置,因此適合建立不規則二維陣列。- 常見錯誤是把
int *plist[5]誤認為真正連續的二維陣列;它本質上是「指標陣列」。
(B)Inorder 轉 Postorder 與二元樹
核心觀念
原式為:
運算優先順序為:
同一層級的 *、/、+、- 皆採由左至右結合,因此原式可分組為:
二元樹
+
/ \
* /
/ \ / \
A B * +
/ \ / \
C - F H
/ \
D E
Postorder 結果
Postorder 的走訪順序為:
因此:
第 6 題10 分
使用 linked list 實作 stack,運用以下 C 語言程式:
typedef struct node { int value; node *next; }
void push(node **top, int new_value) { // assume top is not null
node *new_node = (node *) malloc (sizeof(node));
// 實作以下敘述
// add new_node to stack by top
}
int pop(node **top) { // assume top is not null
int value;
node *deleting_node = *top;
// 實作以下敘述
// remove the deleting node from stack, get the value of deleting node
free(deleting_node);
return value;
}
登入後即可作答並保存紀錄。
第 7 題15 分
使用 stack 解決老鼠走迷宮問題(Maze path search),設計並描述如何實作,包含:
(A) 如何搜尋四個方向來移動
(B) 如何找到合法移動和出口
(C) 解決死路問題
登入後即可作答並保存紀錄。