112 年 國立中正大學資訊工程學系碩士班甲組《軟體設計》
第 1 題10 分
- (10%) 請為下列各項撰寫單行 C 語言敘述式。
(a) (5%) 以八進位制格式,並且以前面加 0 的方式,顯示十進位數值 100。
(b) (5%) 連續讀入字元到陣列 n 中,直到遇到一個非數字字元為止。
登入後即可作答並保存紀錄。
此題考察 C 語言的格式化輸出與字串處理。
(a) 題目要求以八進位制格式顯示十進位數值 100,並在前面加上 0。在 C 語言中,printf 函數的格式化輸出可以滿足此需求。八進位格式化符為 %o,而要在數字前補零則使用 %0 加上數字的總寬度。由於題目沒有指定總寬度,但要求「前面加 0」,通常是指在數字本身前面加上 0,例如 0144。若要顯示為 0144,則需指定總寬度。然而,標準的八進位格式化輸出,如 printf("%o", 100); 會輸出 144。若要強制前面加上 0,例如 0144,則可以透過指定寬度並補零來達成。例如,如果我們假設總寬度為 4,那麼 printf("%04o", 100); 會輸出 0144。如果題目僅要求「顯示為八進位,且前面加 0」,最直接的理解是直接輸出八進位表示,並在前面加上 0 作為前綴。然而,C 語言標準庫的 printf 函數本身並不會自動為八進位數值添加前綴 0。如果我們需要輸出 0144,則需要自行處理。一種方式是使用 %#o,它會輸出 0 作為八進位前綴,例如 printf("%#o", 100); 會輸出 0144。
第 2 題10 分
- (10%) 請回答以下 C 語言程式碼執行後在螢幕上顯示之結果。
#include <stdio.h>
int main() {
char s[]="01234";
char *p=s;
printf("%c",*p++);
printf("%c",*++p);
printf("%c",*(++p));
printf("%c",*(p++));
printf("%c", (*p)++);
return 0;
}
登入後即可作答並保存紀錄。
此題考察 C 語言指標運算、陣列與 printf 的格式化輸出,特別是前遞增 (++p)、後遞增 (p++) 和解引用 (*p) 的組合使用。
程式碼首先定義了一個字元陣列 s,內容為 "01234",並初始化一個字元指標 p 指向陣列的起始位置。此時 p 指向 s[0],即字元 '0'。
讓我們一步一步追蹤 printf 的執行:
-
printf("%c",*p++);p指向s[0]('0')。*p++:這是一個後遞增操作。首先解引用p,取得s[0]的值 '0'。然後p再遞增,指向s[1]。- 輸出:'0'
p現在指向s[1]('1')。
-
printf("%c",*++p);++p:這是一個前遞增操作。p首先遞增,指向s[2]('2')。然後解引用p,取得s[2]的值 '2'。- 輸出:'2'
p現在指向s[2]('2')。
-
printf("%c",*(++p));++p:這是另一個前遞增操作。p首先遞增,指向s[3]('3')。然後解引用p,取得s[3]的值 '3'。- 輸出:'3'
p現在指向s[3]('3')。
-
printf("%c",*(p++));*(p++):這是一個後遞增操作。首先解引用p,取得s[3]的值 '3'。
第 3 題5 分
- (5%) 請回答以下 C 語言程式碼執行後在螢幕上顯示之結果。
#include <stdio.h>
int main() {
int x = 3, n = 6;
for (int i=1; i<=n; i=i+1){
for (int j=1; j<=n; j=j+1) {
if ((i+j)==2)
x = x + 3;
if ((i+j)==3)
x = x + 4;
if ((i+j)==4)
x = x + 5;
}
}
printf ("%d\n", x);
return 0;
}
登入後即可作答並保存紀錄。
此題考察 C 語言的巢狀迴圈、條件判斷以及變數的累加。
程式碼初始化 x = 3 和 n = 6。
外層迴圈 for (int i=1; i<=n; i=i+1) 會從 i = 1 執行到 i = 6。
內層迴圈 for (int j=1; j<=n; j=j+1) 會從 j = 1 執行到 j = 6。
因此,內層迴圈會執行 n * n = 6 * 6 = 36 次。
在內層迴圈中,根據 i+j 的值來更新 x:
- 如果
i+j == 2,則x = x + 3。 - 如果
i+j == 3,則x = x + 4。 - 如果
i+j == 4,則x = x + 5。
我們需要計算 i+j 等於 2、3、4 的總次數。
由於 i 和 j 的範圍都是從 1 到 6,i+j 的最小值是 1+1=2,最大值是 6+6=12。
情況 1: i+j == 2
- 唯一組合是
i=1, j=1。 - 此組合會執行
x = x + 3。 - 總共執行 1 次。
第 4 題4 分
- (4%) John is annoyed that he always needs to keep track of the sizes of integer arrays that he passes
around as pointers. He decides that to make things easier, he will NULL-terminate his integer arrays, just
like strings are NULL-terminated. Specifically, he will use 4 NULL bytes, since on his machine integers are
4 bytes.
Besides taking extra space, what is one issue with John's proposal?
登入後即可作答並保存紀錄。
核心觀念
這題考察「哨兵值(sentinel value)」與 C 語言陣列結尾標記的限制。
字串以 '\0' 作為結尾,是因為字串內容通常不把空字元視為一般文字內容。若將整數陣列也以特殊值標記結尾,則必須保證該值不會出現在有效資料中,否則程式無法區分:
- 陣列中的有效元素;
- 陣列結束標記。
解題方法
John 將陣列配置成如下形式:
int a[] = {10, 20, 30, 0};
並以整數值 0 作為結尾標記。接收指標的函式可能依序讀取:
while (*p != 0) {
/* 使用 *p */
p++;
}
當陣列本身合法包含 0 時,例如:
int a[] = {10, 0, 20, 30, 0};
函式讀到中間的 0 就會誤判陣列已結束,因此只處理 10,漏掉後面的 20 與 30。
第 5 題3 分
- (3%) (Check all that apply. NO partial credit is given.)
Which of the following are declarations but not definitions?
(A) int i;
(B) int i=1;
(C) int foo(int);
(D) int foo(int i);
(E) typedef string my_string;
(F) None of the above
登入後即可作答並保存紀錄。
核心觀念
本題考查「宣告(declaration)」與「定義(definition)」的區別:
- 宣告:告知編譯器名稱、型別或函式介面,使編譯器知道它的存在。
- 定義:除了宣告之外,還會建立物件、配置儲存空間,或提供函式的實作內容。
函式若只有函式名稱、參數與回傳型別,沒有函式本體 {...},就是函式宣告,不是函式定義。
typedef 則是建立型別別名的宣告,不會建立變數或函式,也不是物件定義。
解題方法
逐一判斷每個選項是否:
- 建立變數並配置儲存空間;
- 提供變數初值;
- 提供函式本體;
- 建立型別別名。
符合「只有告知資訊,沒有建立物件或提供實作」者,就是「宣告但不是定義」。
選項分析
(A) int i;
這是整數變數 i 的宣告,同時也是變數定義。
在函式內宣告時,會建立區域變數;在檔案層級時,屬於暫定定義(tentative definition),仍視為物件定義。因此不是本題答案。
(B) int i=1;
這是變數 i 的定義,並且初始化為 。它會建立變數並配置儲存空間,因此不是單純宣告。
(C) int foo(int);
這是函式 foo 的函式原型宣告:
- 回傳型別為
int; - 接受一個
int型別的參數; - 沒有函式本體。
第 6 題12 分
- (12%) (Check all that apply. NO partial credit is given.)
甲. (3%) Which of the following is TRUE about the special variable "this"?
(A) It is a reference value.
(B) You are allowed to change what it points to within a method.
(C) It is point to the calling instance of a method.
(D) All of the above
(E) None of the above
乙. (3%) For a class named Thing, what is the type of the implicit this?
(A) Thing
(B) Thing * const
(C) const Thing * const
(D) Thing *
(E) Depends on if the member function is const.
(F) None of the above
丙. (3%) Which of the following are TRUE about a const variable?
(A) You can still assign a value to a const variable by using a reference variable associated with the
const variable.
(B) It must be initialized at the time of declaration.
(C) You cannot add const to a reference variable associated with non-const variable.
(D) All of the above
(E) None of the above
丁. (3%) Which of the following cause a string to be copied (presuming y is a string)?
(A) const string * x = y;
(B) const string & x = y;
(C) const string * const x = y;
(D) string & x = y;
(E) string * x = y;
(F) None of the above
登入後即可作答並保存紀錄。
核心觀念
本題考查 C++ 中下列觀念:
this是成員函式內建的指標,指向目前呼叫該成員函式的物件。this本身不能被重新指定。const變數必須初始化,且不能透過別名被修改。- 參考變數不會建立副本;指標宣告也不會因為指定位址而複製物件。
甲、特殊變數 this
解題方法
在非靜態成員函式中,this 代表目前物件的位址。以類別 Thing 為例,非 const 成員函式中的 this 型別可視為:
也就是「不可改變的指標」,但指標所指向的物件本身可以被修改。
選項分析
-
(A) 錯誤:
this是指標值,不是 reference value。它儲存的是目前物件的位址。 -
(B) 錯誤:
this本身不可被重新指定,例如不能寫成:this = &anotherObject; -
(C) 正確:
this指向呼叫該成員函式的物件,也就是 calling instance。 -
(D) 錯誤:因為 (A)、(B) 錯誤,不能選 All of the above。
-
(E) 錯誤:至少 (C) 正確,因此不能選 None of the above。
解題技巧
看到 this 時記住:
this是「指向目前物件的不可重新指定指標」。
因此「指向呼叫實例」正確,「可以改變它指向的物件」錯誤。
【答案】(C)
乙、隱含 this 的型別
解題方法
假設類別名稱為 Thing:
-
一般成員函式:
Thing* const this; -
const成員函式:const Thing* const this;
this 的最外層指標本身不可改變;若成員函式是 const,則它指向的物件也視為 const。
選項分析
- (A)
Thing:錯誤。這是物件型別,不是this的指標型別。 - (B)
Thing * const:僅適用於非const成員函式,不能涵蓋所有成員函式情況。 - (C)
const Thing * const:僅適用於const成員函式,也不能涵蓋一般成員函式。 - (D)
Thing *:錯誤。忽略了this指標本身不可重新指定的const屬性。 - (E) 正確。
this的完整型別取決於成員函式是否宣告為const。 - (F) 錯誤:因為 (E) 正確。
解題技巧
本題關鍵是分辨兩個 const:
Thing* const
表示指標不能改指向別處;
const Thing* const
表示指標不能改指向別處,且不能透過它修改 Thing 物件。
【答案】(E)
丙、const 變數
核心觀念
const 變數一旦初始化,就不能再被修改:
const int x = 10;
此外,const 是加在被參照型別上,而不是加在 reference 本身。C++ 的 reference 沒有「重新繫結」或「reference 本身為 const」的獨立意義。
選項分析
-
(A) 錯誤:不能透過 reference 修改
const變數:const int a = 10; const int& r = a;
第 7 題6 分
- (6%) (Select all correct answers. NO partial credit is given.)
甲. (3%) Constructors:
(A) Are called when the instance goes out of scope or is de-allocated.
(B) Can be used to set data members to a known initial value / state.
(C) Can be overloaded (i.e., multiple constructors with different argument lists)
(D) Are called automatically only when the instance is allocated dynamically with 'new and not
when the instance is declared statically as a local variable.
(E) None of the above
乙. (3%) What is the return type of a class constructor?
(A) An instance of the class
(B) No return on a constructor
(C) An int (the size of the class in bytes)
(D) A string (the name of the class)
(E) None of the above
登入後即可作答並保存紀錄。
此題組考察 C++ 中的建構子 (Constructor) 的概念。
甲. (3%) 建構子 (Constructors)
建構子是 C++ 中用於初始化物件的特殊成員函數。
- (A) Are called when the instance goes out of scope or is de-allocated.
- 錯誤。當物件超出作用域或被銷毀時,調用的是解構子 (Destructor),而不是建構子。
- (B) Can be used to set data members to a known initial value / state.
- 正確。建構子的主要目的是初始化物件的資料成員,確保物件在創建時處於一個有效的初始狀態。
- (C) Can be overloaded (i.e., multiple constructors with different argument lists)
- 正確。一個類別可以有多個具有不同參數列表的建構子,這稱為建構子的多載 (overloading)。這允許物件以不同的方式初始化。
- (D) Are called automatically only when the instance is allocated dynamically with 'new and not
when the instance is declared statically as a local variable.
第 8 題10 分
- (10%) Please examine the five sentences and give your answer, true (T) or false (F), for each sentence.
Two points are given for each correct answer.
(1) (2%) The maximum number of nodes in a binary tree with nine levels is 511.
(2) (2%) If and , then .
(3) (2%) The lower bound of worst-case time complexity of comparison-based sorting algorithm is
.
(4) (2%) A bi-connected graph is a connected graph that has two articulation points.
(5) (2%) Every binary tree can be uniquely defined by its pre-order and post-order sequences.
登入後即可作答並保存紀錄。
此題考察資料結構與演算法的基礎概念,包括樹的性質、時間複雜度、圖論以及樹的遍歷。
1. (2%) 具有九個層級的二元樹節點的最大數量
- 觀念: 在二元樹中,層級 (level) 通常從 0 或 1 開始計算。如果層級從 0 開始,則第 k 層最多有 個節點。樹的高度 (height) 是指從根節點到最深葉節點的最長路徑上的邊數。層數 (number of levels) 是高度 + 1。
- 如果題目中的「九個層級」指的是樹的高度為 8 (即有 9 層,從層 0 到層 8),那麼總節點數是 。
- 如果題目中的「九個層級」指的是樹的高度為 9 (即有 10 層,從層 0 到層 9),那麼總節點數是 。
- 通常,在談論樹的層級時,如果說「有 n 個層級」,通常是指從第 1 層到第 n 層。如果從第 1 層開始,那麼第 k 層最多有 個節點。總節點數為 。
- 另一種常見定義是:層級 0 根節點,層級 1 子節點...。如果「九個層級」是指最大的層級索引是 8 (即層級 0, 1, ..., 8),那麼總共有 9 層。最大節點數為滿二元樹,總節點數為 。
- 如果「九個層級」是指樹的高度為 9 (即從根到最深葉節點的路徑上最多有 9 條邊),那麼這棵樹最多有 10 層 (層級 0 到 9)。最大節點數為 。
- 基於常見的定義,如果說「有九個層級」,通常是指從第 1 層到第 9 層,或者層級索引從 0 到 8。如果層級從 0 開始,第 9 層的節點數是 。總節點數是 。
- 假設「九個層級」是指從層級 0 到層級 8,總共 9 層。 在滿二元樹中,層級 k 最多有 個節點。總節點數為 。
- 結論: 這種情況下,敘述為 True。
2. (2%) 和 ,則
- 觀念: 表示一個漸進上界。如果 且 ,這意味著 和 的成長速度都慢於或等於 的成長速度。但這並不意味著 和 是相同的函數。
- 反例: 設 。
- 令 。則 是正確的。
- 令 。則 是正確的。
- 但是,。
第 9 題15 分
- (15%) Please examine each question's four answer options and select the best one. Three points are
given for each correct answer.
(1) (3%) Which sequence will we get if we traverse the following graph with Depth-First Search from
node 1? Note that the node with a smaller ID will be considered and visited first.
🖼️【此處有附圖,請對照原卷】
a. 1, 12, 10, 6, 11, 2, 9, 5, 4, 3, 7, 8
b. 1, 5, 8, 11, 12, 9, 7, 2, 6, 10, 3, 4
c. 1, 12, 11, 8, 5, 10, 7, 6, 2, 9, 4, 3
d. 1, 5, 9, 2, 6, 7, 8, 12, 10, 11, 3, 4
(2) (3%) What will we get after we heapify the integer array {19, 5, 27, 3, 16, 11, 69, 18} to a Max
Heap in time? Note that we use the bottom-up method.
a. {69, 27, 19, 18, 16, 11, 5, 3}
b. {69, 18, 27, 5, 16, 11, 19, 3}
c. {69, 18, 27, 16, 5, 11, 19, 3}
d. {3, 5, 11, 16, 18, 19, 27, 69}
(3) (3%) Please select the result after we add the integers {89, 70, 52, 4, 25, 99, 59, 20, 79, 62, 44,
38} sequentially to an AVL tree.
🖼️【此處有附圖,請對照原卷】
(4) (3%) Please select the correct number of distinct binary trees with 8 nodes.
a. 1430
b. 132
c. 429
d. 4862
(5) (3%) Please select the result after we add the integers {50, 10, 80, 90, 70, 60, 65, 62}
sequentially to a red-black tree. Note that the following white and black circles represent the
red and black nodes in red-black trees, respectively.
🖼️【此處有附圖,請對照原卷】
登入後即可作答並保存紀錄。
核心觀念
本題綜合考查:
- Graph 的 Depth-First Search(DFS)
- Max Heap 的 bottom-up heapify
- AVL Tree 插入與旋轉
- Catalan number 與二元樹數量
- Red-Black Tree 插入、重新著色與旋轉
(1) DFS
解題方法
從節點 開始,每次都選擇尚未拜訪且編號最小的相鄰節點;若目前節點沒有尚未拜訪的鄰點,就回溯到上一層。
依照圖中的連線,DFS 拜訪順序為:
完成 的搜尋後回溯,再拜訪 ;接著回溯至 ,拜訪 與 :
選項分析
- a. 錯誤。從節點 出發時,最小的優先鄰點應先走向 ,不是 。
- b. 錯誤。走到節點 後,依編號應先拜訪 ,不是 。
- c. 錯誤。第一步即選擇 ,不符合從節點 選擇最小編號鄰點的規則。
- d. 正確,符合 DFS 的深入與回溯順序。
解題技巧
DFS 題目要同時注意:
- 使用堆疊概念深入搜尋。
- 鄰點選擇順序會影響整個拜訪序列。
- 已拜訪節點不可重複列入序列。
- 遇到死路時必須回溯,不能直接跳到任意尚未拜訪節點。
【答案】d
(2) Bottom-up Max Heapify
核心觀念
Max Heap 必須滿足:
Bottom-up heapify 從最後一個非葉節點開始調整。陣列共有 個元素,因此最後一個非葉節點為:
原陣列:
解題步驟
從索引 開始:
- 調整節點 ,其子節點為 :
- 調整節點 ,其子節點為 ,與較大的 交換:
- 調整節點 ,其子節點為 ,與 交換:
- 調整根節點 ,先與較大的子節點 交換:
接著節點 與子節點 交換:
因此 Max Heap 為:
選項分析
- a. 錯誤。雖然符合 Max Heap 的局部大小關係,但不是此陣列使用 bottom-up heapify 後的結果。
- b. 正確,且每個父節點皆不小於其子節點。
- c. 錯誤。節點 的子樹排列與實際 sift-down 結果不符。
- d. 錯誤。這是遞增排序結果,不是 Max Heap 的陣列表示。
解題技巧
Heapify 時,每次都要與「較大的子節點」交換,否則無法保證 Max Heap 性質。Bottom-up heapify 的時間複雜度為:
【答案】b
(3) AVL Tree 插入
核心觀念
AVL Tree 必須滿足每個節點的平衡因子:
且必須滿足:
當插入造成失衡時,使用 LL、RR、LR 或 RL 旋轉修正。
解題方法
依序插入:
關鍵旋轉如下:
- 插入 後, 發生 LL 失衡,右旋。
- 插入 後,節點 發生 LR 失衡,先左旋再右旋。
- 插入 後,造成以 為根的 LR 失衡,進行雙旋轉,形成以 為根的結構。
第 10 題8 分
True or False
(a) (2%) Quicksort is asymptotically optimal.
(b) (2%) When sorting numbers, if a series of pivot selections make the partitioning of Quicksort maximally unbalanced at every recursive level, the corresponding decision tree is a full binary tree.
(c) (2%) Insertion sort is in-place but not stable.
(d) (2%) Counting sort has both stable and in-place properties.
登入後即可作答並保存紀錄。
核心觀念
- 漸近最佳:比較排序的下界為 ;若演算法的最壞情況時間也達到 ,稱為漸近最佳。
- Decision tree:內部節點代表一次比較(兩種結果),葉節點代表一種輸出排列。它描述的是演算法所有可能的比較結果,與 Quicksort 的遞迴樹是不同的東西。
- Full binary tree:每個節點恰有 0 或 2 個子節點。
- In-place 指額外空間為 (或很小);stable 指相等鍵值的相對順序保持不變。
選項分析
(a) Quicksort is asymptotically optimal. → False
Quicksort 平均為 ,但最壞情況為 ,沒有達到比較排序的 最壞情況下界所對應的 ;Merge sort、Heapsort 才是最壞情況也達到的漸近最佳排序。
(b) 每層分割都最不平衡時,對應的 decision tree 是 full binary tree。 → True
不論 pivot 如何選,Quicksort 的每個比較都會產生「小於」與「不小於」兩種結果,decision tree 的每個內部節點因此恰有兩個子節點,葉節點對應各種排列。最不平衡的分割只會讓這棵樹的某些路徑特別長(樹很歪、很深),不會讓內部節點只剩一個子節點。所以它是 full binary tree。把每次分割成 與 兩份的情形當成「degree 1」是把遞迴樹與 decision tree 混為一談。
第 11 題11 分
Yes/No questions about the graph at the right side. Write down your reasoning. A simple yes/no answer will not get any point.
🖼️【此處有附圖,請對照原卷】
(a) (2%) To find a shortest path from node to node , is Dijkstra algorithm applicable?
(b) (2%) If all the edges have weight , is breadth-first search applicable to find a shortest path from node to node ?
(c) (2%) If all the edges have weight , is topological sort applicable to the graph?
(d) (5%) Reweight the graph to make all the edges nonnegative.
登入後即可作答並保存紀錄。
核心觀念
Dijkstra 演算法的標準適用條件是所有邊權重皆非負;廣度優先搜尋(BFS)可在所有邊權重相同時,依邊數找最短路徑;拓樸排序則只適用於有向無環圖(DAG)。若以頂點勢能重新加權,公式為 ,可在邊權重變成非負的同時保留最短路徑的相對順序。
解題方法與各小題分析
圖中有向邊及權重為: 權重 、 權重 、 權重 、 權重 、 權重 。
(a) 否。 圖中有負權邊,違反 Dijkstra 演算法的標準適用條件,因此不能用它保證求得最短路徑。此圖從 到 的最短路徑為 ,權重總和是 ;但即使某次執行碰巧得到正確結果,也不代表 Dijkstra 對含負權邊的圖適用。
(b) 是。 若每條邊的權重都設為 ,路徑權重總和就等於路徑所經過的邊數。BFS 會依距離起點的邊數逐層搜尋,因此可用來找從 到 的最短路徑。例如 經過兩條邊。
第 12 題6 分
What is the output when applying Ford-Fulkerson algorithm to the following graph? Write down your derivation.
🖼️【此處有附圖,請對照原卷】
登入後即可作答並保存紀錄。
核心觀念
Ford–Fulkerson 演算法反覆在殘餘網路中尋找從源點 到匯點 的增廣路徑。每次沿路徑增加的流量,等於該路徑上最小的剩餘容量;當找不到增廣路徑時,即得到最大流。
解題方法
圖中有四個節點:源點 、右上節點、左下節點及匯點 。有向邊與容量依序為: 到右上節點容量 、 到左下節點容量 、 到 容量 、右上節點到左下節點容量 、右上節點到 容量 ,以及左下節點到 容量 。
依序選擇以下增廣路徑:
- :瓶頸容量為 ,增加流量 。
- 右上節點:瓶頸容量為 ,增加流量