108 年 國立臺灣大學工程科學及海洋工程學系碩士班丁組《資料結構(A)》
第 1 題10 分
(10%) Please convert the following infix expressions to postfix:
(a) (5%)
(b) (5%)
登入後即可作答並保存紀錄。
核心觀念
中序式(infix)將運算子放在兩個運算元之間,例如 ;後序式(postfix)則將運算子放在其運算元之後,例如 。
轉換時遵守:
- 括號優先處理,括號本身不輸出。
- 乘法與除法優先於加法與減法。
- 同一優先權由左至右計算。
- 後序式中,每個運算子都接在其完整運算子之前。
運算子優先權如下:
解題方法
採用「運算子堆疊法」:
- 運算元直接輸出。
- 左括號 推入堆疊。
- 遇到右括號 ,持續彈出並輸出堆疊頂端運算子,直到遇到左括號;再將左括號移除。
- 遇到運算子時,若堆疊頂端已有相同或更高優先權的運算子,先彈出輸出,再將目前運算子推入。
- 掃描結束後,將堆疊中剩餘運算子依序彈出。
(a)
原式的運算結構為:
轉換步驟:
- 讀到 ,直接輸出:
- 讀到 ,推入堆疊。
- 讀到左括號,推入堆疊。
- 讀到 ,輸出:
- 讀到 ,推入堆疊。
- 讀到 ,輸出:
- 讀到右括號,彈出 ,輸出:;移除左括號。
- 讀到 。堆疊頂端為 ,且 與 優先權相同,依左至右規則先輸出 :
- 將 推入堆疊。
- 讀到 ,輸出:
- 掃描結束,彈出 。
因此:
不加空格時為:
(b)
原式的運算結構為:
轉換步驟:
- 讀到 ,輸出:
- 讀到 ,推入堆疊。
- 讀到左括號,推入堆疊。
- 讀到 ,輸出:
- 讀到 ,推入堆疊。
- 讀到 ,輸出:
- 讀到 。堆疊頂端為 ,優先權較高,先輸出 :
- 將 推入堆疊。
- 讀到 ,輸出:
第 2 題15 分
Write a method called makeList in a SList class with a tail. The makeList function takes an array counts of int, constructs a singly-linked list, and associates its head and tail pointers to the corresponding SListNode nodes. In the constructed list, the first counts[0] items are the number counts[0], the next counts [1] items are the number counts[1], etc. For example, if the input array is {1 3 2}, then the output linked list is: head→ 1 →3→3→3→2→2→tail. Define the SList and SListNode classes to complete the make List method. When it is done, the size of nodes in SList should also be updated accordingly.
登入後即可作答並保存紀錄。
核心觀念
本題考查:
- 單向鏈結串列(Singly Linked List)
- 頭指標
head與尾指標tail的維護 - 尾端插入(append)
- 鏈結串列節點數量
size的更新
給定陣列 counts 後,對每個索引 :
- 建立
counts[i]個節點; - 每個節點的資料值都設為
counts[i]。
因此,若:
counts = {1, 3, 2}
則建立:
1 → 3 → 3 → 3 → 2 → 2
最後:
head指向第一個節點;tail指向最後一個節點;size = 1 + 3 + 2 = 6。
尾指標 tail 指向最後一個節點,而不是額外建立的虛擬節點;最後一個節點的 next 應為 null。
解題方法
建立節點時,分成兩種情況處理。
情況一:串列目前為空
若 head == null,代表這是建立的第一個節點,因此:
head = newNode
tail = newNode
此時頭尾指標都指向同一個節點。
情況二:串列已有節點
若串列已經有節點,將新節點接在尾端:
tail.next = newNode
tail = newNode
每建立一個節點,就將:
size++
如此即可同步維護節點數量。
完整類別與方法
以下以 Java 語法實作:
class SListNode {
int data;
SListNode next;
SListNode(int data) {
this.data = data;
this.next = null;
}
}
class SList {
SListNode head;
SListNode tail;
int size;
public SList() {
head = null;
tail = null;
size = 0;
}
public void makeList(int[] counts) {
// 重新建立串列前,先初始化串列狀態
head = null;
tail = null;
size = 0;
for (int i = 0; i < counts.length; i++) {
int value = counts[i];
if (value < 0) {
throw new IllegalArgumentException(
"counts 中的元素不可為負數"
);
}
// 建立 value 個資料值為 value 的節點
for (int j = 0; j < value; j++) {
SListNode newNode = new SListNode(value);
if (head == null) {
// 建立第一個節點
head = newNode;
tail = newNode;
} else {
// 接到尾端
tail.next = newNode;
tail = newNode;
}
size++;
}
}
}
}
第 3 題10 分
Examine the following statements. If it is correct, prove it. If it is incorrect, show the contradiction.
(a) (5%)
(b) (5%)
登入後即可作答並保存紀錄。
核心觀念
本題考查漸進符號的定義:
-
:存在常數 與 ,使得對所有 ,
-
:存在常數 與 ,使得對所有 ,
判斷時只需考慮 足夠大時的成長率,有限個小 值不影響 或 的判定。
解題方法與選項分析
(a)
此敘述正確。
當 時,
因此,
取 、,即可符合 的定義:
所以,
事實上,當 足夠大時,
而 ,故原敘述成立。
(b)
此敘述錯誤。
對足夠大的 ,有 ,因此
取倒數後得
第 4 題10 分
Show the sequence of swaps by which the method bottomUpHeap converts the following array into a min heap. Redraw the array once for each swap.
7 2 6 9 3 5 1 8
登入後即可作答並保存紀錄。
核心觀念
本題考查以 bottom-up heap construction 建立最小堆積(min heap)。
採用 1-based indexing 時:
- 節點 的左子節點為
- 右子節點為
- 節點 的父節點為
- 最後一個非葉節點為
建立最小堆積時,從最後一個非葉節點開始,依序對
執行向下調整(sift-down)。每次將目前節點與其值最小的子節點比較;若目前節點較大,就交換,並繼續向下調整。
解題方法
原始陣列共有 個元素,因此最後一個非葉節點為
處理順序為 。
原始陣列:
1. 處理索引 4
索引 4 的值為 ,其子節點為索引 8,值為 。
因為 ,交換索引 4 與索引 8:
索引 8 已是葉節點,調整結束。
2. 處理索引 3
索引 3 的值為 ,其子節點為:
- 索引 6:
- 索引 7:
兩個子節點中較小者為 。因為 ,交換索引 3 與索引 7:
索引 7 為葉節點,調整結束。
3. 處理索引 2
索引 2 的值為 ,其子節點為:
- 索引 4:
- 索引 5:
最小子節點為 。因為 ,已符合最小堆積條件,不需交換:
4. 處理索引 1
索引 1 的值為 ,其子節點為:
- 索引 2:
- 索引 3:
最小子節點為 。因為 ,交換索引 1 與索引 3:
第 5 題15 分
Write a recursive method preorderElementAt(int k) that returns the kth element in the preorder listing of the subtree in a binary tree. For example, if k = 1, return the element in the root node. The method should run in O(d) time, where d is the depth of the subtree. If the subtree doesn't have k nodes, return null. Define all necessary classes and associated fields to accomplish the function.
登入後即可作答並保存紀錄。
解題關鍵
- 前序遍歷順序:根 → 左子樹 → 右子樹。
- 若每個節點保存其整個子樹的節點數
subtreeSize,則可在 ( 為子樹深度)內定位第 個節點:
類別與欄位
public class TreeNode<E> {
E element; // 節點儲存的資料
TreeNode<E> left, right; // 左、右子節點
int subtreeSize; // 以此節點為根的子樹節點總數(含自身)
public TreeNode(E e) {
element = e;
left = right = null;
subtreeSize = 1; // 初始只有自己
}
// 更新 subtreeSize,通常在插入/刪除時呼叫
void updateSize() {
int l = (left != null) ? left.subtreeSize : 0;
int r = (right != null) ? right.subtreeSize : 0;
subtreeSize = 1 + l + r;
}
}
遞迴方法
第 6 題12 分
A graph G is bipartite if its vertices can be partitioned into two sets X and Y such that every edge in G has one end vertex in X and the other in Y. Describe (not code) an efficient algorithm for determining if an undirected graph G is bipartite (without knowing the sets X and Y in advance).
登入後即可作答並保存紀錄。
核心觀念
二分圖(bipartite graph)的定義是:可以將所有頂點分成兩個互斥集合 與 ,使每條邊的兩端分別位於 與 。
等價地,二分圖可以使用兩種顏色為頂點著色,使得每條邊連接不同顏色的頂點。因為若將兩種顏色的頂點分別放入 與 ,即可得到二分圖的兩個集合。
判定的關鍵原則為:
- 與某頂點距離為偶數的頂點使用同色。
- 與某頂點距離為奇數的頂點使用異色。
- 若發現某條邊的兩端已被分配相同顏色,則圖形不是二分圖。
此方法也等價於判斷圖中是否含有奇數長度的環:
解題方法
採用 BFS 或 DFS 進行圖形走訪,並在走訪過程中進行二色著色。
令每個頂點的顏色為:
- 未著色
- 顏色
- 顏色
演算法步驟如下:
- 將所有頂點設為未著色。
- 逐一檢查每個頂點。若某頂點尚未著色,將它指定為顏色 ,並從該頂點開始 BFS 或 DFS。
- 走訪目前頂點 的每一條邊 :
- 若 尚未著色,將 設為與 不同的顏色,即 然後繼續走訪 。
- 若 已著色,檢查是否滿足
- 若 ,表示存在衝突,立即判定 不是二分圖。
- 若所有連通元件都完成走訪且沒有發生衝突,則判定 是二分圖。此時可將顏色 的頂點放入 ,顏色 的頂點放入 。
必須逐一處理所有尚未著色的頂點,因為無向圖可能不是連通圖。每個連通元件都必須分別進行二色著色。
正確性說明
第 7 題16 分
Sorting.
(a) (8%) Trace the bubble sort as it sorts the following array into ascending order:
15 4 2 27 10
(b) (8%) Is the bucket-sort algorithm in-place? Why or why not?
登入後即可作答並保存紀錄。
核心觀念
本題考查兩種排序法:
- Bubble sort:反覆比較相鄰元素,若左值大於右值便交換,使較大的元素逐步往陣列右側移動。
- Bucket sort:先將資料依值域分配至多個桶子,再分別排序各桶並串接;判斷是否為 in-place 的重點,在於是否需要與輸入陣列大小無關的額外儲存空間。
(a) Bubble sort 排序過程
初始陣列為:
採用由左至右掃描的標準 Bubble sort,每一輪結束後,當輪最大的未排序元素會固定在最右側。
第 1 輪
依序比較相鄰元素:
- 比較 與 :
- 比較 與 :
- 比較 與 :
- 比較 與 :
第 1 輪結束:
此時最大值 已固定在最後位置。
第 2 輪
只需處理前四個元素:
- 比較 與 :
- 比較 與 :
- 比較 與 :
第 2 輪結束:
此時 已固定在倒數第二個位置。
第 3 輪
處理前面三個元素:
第 8 題12 分
Suppose you insert a set of keys {4, 6, 12, 15, 3, 5} into an initially empty 2-3-4 tree in that order. Now, you do the same insertion to an empty 2-3-4 tree with the same keys but a different order, say {12, 3, 6, 4, 5, 15}. Can these two trees have the same structure? Draw both trees to justify your answer.
登入後即可作答並保存紀錄。
核心觀念
2-3-4 樹是階數為 的 B-tree,具有以下性質:
-
每個節點最多含 個鍵值。
-
節點內鍵值皆由小到大排列。
-
除根節點外,每個內部節點至少含 個鍵值。
-
所有葉節點位於同一層。
-
插入時,若即將進入的節點已含 個鍵值,必須先分裂:
也就是將中間鍵值 提升至父節點。
本題考查「插入順序是否必然造成不同的 2-3-4 樹結構」。答案取決於每次分裂時被提升的鍵值與最後各子樹的分布。
解題方法:第一種插入順序
插入順序為:
- 插入 :
- 插入 前,根節點已滿,先分裂:
再將 插入右子節點:
- 插入 :
- 插入 :
因此第一棵樹為:
[6]
/ \
[3, 4, 5] [12, 15]
解題方法:第二種插入順序
插入順序為:
- 插入 :