112 年 國立中山大學電機工程學系碩士班丙組《資料結構》

📄 試題原卷 免費註冊後即可對照原始考卷 PDF免費註冊

第 1 題

【此題30分;每一小題10分】

  1. 我們用 n≥0n \ge 0 表示演算法A的input size,用 T(n)≥0T(n) \ge 0 表示演算法A的執行時間。假設 T(n)T(n) 的時間複雜度(time complexity)為 Θ(f(n))\Theta(f(n))。寫出 f(n)f(n) 的數學定義。
  2. 假設演算法 B 和演算法 C 都能解決問題 Q, 但演算法 B 的執行時間為 Θ(log⁡n)\Theta(\log n), 演算法 C 的執行時間為 Θ((log⁡(log⁡n))!)\Theta((\log(\log n))!), 其中 nn 為 input size。假設 nn 的值很大, 並且我們用時間複雜度來判斷演算法的好壞, 那我們該選用哪一個演算法來解決問題 Q 呢? 解釋你的立論根據; 直接寫答案, 此一小題以0分計算。
  3. 圖1 是使用跟「C 程式語言」類似的語法描述 insertion sort, 其中 DD 表示陣列的名稱, 其元素皆為整數, 而 nn 為陣列裡頭的元素數量。此一 insertion_sort 函式(function)能夠將陣列裡的元素由小到大排序。我們用 T(n)T(n) 表示 insertion_sort 函式的執行時間。那麼「T(n)=Θ(n2)T(n) = \Theta(n^2)」這樣的說法是否正確? 解釋你的立論根據; 若未解釋, 此小題以0分計算。
void insertion_sort(int D[], int n) {
  for (int i = 1; i < n; i++) {
    int key = D[i];
    int j = i - 1;
    while ((j >= 0) and (D[j] > key)) {
      D[j + 1] = D[j];
      j--;
    }
    D[j + 1] = key;
  }
}

圖1: insertion_sort 函式。

🖼️ 本題含圖表,以下為原卷對應頁面:
原卷第 2 頁原卷第 3 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查漸近緊確界 Θ\Theta 的定義、不同成長率的比較,以及插入排序的執行時間如何受輸入排列影響。

解題方法

1. Θ(f(n))\Theta(f(n)) 的數學定義

若存在正常數 c1,c2c_1,c_2 與正整數 n0n_0,使得所有 n≥n0n\ge n_0 都滿足

0≤c1f(n)≤T(n)≤c2f(n),0 \le c_1 f(n) \le T(n) \le c_2 f(n),

則稱 T(n)=Θ(f(n))T(n)=\Theta(f(n))。

也就是說,當 nn 充分大時,T(n)T(n) 同時有 f(n)f(n) 的漸近下界與上界,兩者只差正常數倍。

2. 比較演算法 B 與 C

依照考卷原圖,演算法 B 的時間複雜度為 Θ(log⁡2n)\Theta(\log^2 n),演算法 C 為 Θ((log⁡log⁡n)!)\Theta((\log\log n)!)。

令 m=log⁡log⁡nm=\log\log n。此時 log⁡2n\log^2 n 可寫成 eΘ(m)e^{\Theta(m)}。由 Stirling 公式,

log⁡(m!)=mlog⁡m−m+O(log⁡m).\log(m!)=m\log m-m+O(\log m).

當 mm 趨近無窮大時,mlog⁡m−mm\log m-m 的成長速度高於任何固定常數倍的 mm,因此 (log⁡log⁡n)!(\log\log n)! 最終會比 log⁡2n\log^2 n 成長得快。

題目以執行時間較低作為較好的判斷標準,所以應選漸近成長較慢的演算法 B。

3. 判斷插入排序是否為 Θ(n2)\Theta(n^2)

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 2 題

【此題25分;第①小題15分,第②小題10分】
假設一個 binary tree, 其 preorder 的拜訪次序為 A→B→D→G→E→C→F, 其 inorder 的拜訪次序為 G→D→B→E→A→C→F。
① 請畫出此一 binary tree。註:必須寫出你推導出這棵 binary tree的過程。直接寫答案,此小題以0分計算。
② 針對此一 binary tree, 寫出 postorder 的拜訪次序。此小題可以直接寫答案。

🖼️ 本題含圖表,以下為原卷對應頁面:
原卷第 2 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

前序走訪順序為「根 → 左子樹 → 右子樹」,中序走訪順序為「左子樹 → 根 → 右子樹」,後序走訪順序為「左子樹 → 右子樹 → 根」。

重建二元樹時,先用前序序列的第一個節點找出根,再從中序序列定位根。根左側是左子樹,根右側是右子樹;依此分割前序序列後,對左右子樹遞迴處理。

解題方法

  1. 前序序列第一個節點是根,因此根為 AA。在中序序列 G→D→B→E→A→C→FG\to D\to B\to E\to A\to C\to F 中,AA 左側的 G,D,B,EG,D,B,E 屬於左子樹,右側的 C,FC,F 屬於右子樹。
  2. 左子樹的前序序列為 B→D→G→EB\to D\to G\to E。其根為 BB;在左子樹的中序序列 G→D→B→EG\to D\to B\to E 中,BB 左側是 G,DG,D,右側是 EE。因此 BB 的左子樹由 D,GD,G 組成,右子節點為 EE。
  3. BB 的左子樹前序序列為 D→GD\to G,故根為 DD;
🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 3 題

【此題15分】針對下列資料序列(sequence)
16、30、8、79、24、51
使用 heap sort 進行排序,並使得輸出結果為「由小到大」的資料序列。註:此題必須畫出排序的每個步驟;若步驟有省略,將視情況予以適量扣分。若直接寫答案,此題以0分計算。

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

Heap sort(堆積排序)將序列視為完全二元樹,並利用堆積的性質排序。

以第 11 格為根節點時:

左子節點=2i,右子節點=2i+1,父節點=⌊i2⌋\text{左子節點}=2i,\qquad \text{右子節點}=2i+1,\qquad \text{父節點}=\left\lfloor\frac{i}{2}\right\rfloor

最大堆積(max heap)的定義為:每個父節點皆不小於其子節點。因此,根節點必定是目前堆積中的最大值。

題目要求由小到大排序,採用最大堆積。每一輪將根節點的最大值與未排序區最後一個元素交換,該最大值即固定在序列尾端,再對剩餘部分向下調整。


解題方法

原始序列為:

[16,  30,  8,  79,  24,  51][16,\;30,\;8,\;79,\;24,\;51]

其完全二元樹如下:

              16
            /    \
          30      8
         /  \    /
       79   24  51

一、建立最大堆積

最後一個非葉節點為:

⌊62⌋=3\left\lfloor\frac{6}{2}\right\rfloor=3

因此從第 33 格、第 22 格、第 11 格依序向上調整。

步驟 1:調整第 3 格

第 3 格為 88,其子節點為第 6 格的 5151,交換:

[16,  30,  8,  79,  24,  51]⟶[16,  30,  51,  79,  24,  8][16,\;30,\;8,\;79,\;24,\;51] \longrightarrow [16,\;30,\;51,\;79,\;24,\;8]

步驟 2:調整第 2 格

第 2 格為 3030,子節點為 79,2479,24,與較大的子節點 7979 交換:

[16,  30,  51,  79,  24,  8]⟶[16,  79,  51,  30,  24,  8][16,\;30,\;51,\;79,\;24,\;8] \longrightarrow [16,\;79,\;51,\;30,\;24,\;8]

步驟 3:調整第 1 格

第 1 格為 1616,子節點為 79,5179,51,先與較大的 7979 交換:

[16,  79,  51,  30,  24,  8]⟶[79,  16,  51,  30,  24,  8][16,\;79,\;51,\;30,\;24,\;8] \longrightarrow [79,\;16,\;51,\;30,\;24,\;8]

此時 1616 下移至第 2 格,其子節點為 30,2430,24,再與較大的 3030 交換:

[79,  16,  51,  30,  24,  8]⟶[79,  30,  51,  16,  24,  8][79,\;16,\;51,\;30,\;24,\;8] \longrightarrow [79,\;30,\;51,\;16,\;24,\;8]

最大堆積建立完成:

              79
            /    \
          30      51
         /  \    /
       16   24  8

二、反覆取出最大值

記號

[尚未排序的堆積∣已排序部分][\text{尚未排序的堆積}\mid\text{已排序部分}]

豎線左側才參與後續堆積調整。

第 1 輪:堆積大小由 6 變為 5

將根節點 7979 與第 6 格的 88 交換:

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 4 題

【此題20分;每一小題10分】
① 圖2為一棵AVL tree。在圖2裡頭插入「73」之後的AVL tree為何?請畫出來。
② 承上題,在插入「73」之後,接著刪除「28」所產生的AVL tree為何?請畫出來。
🖼️【此處有附圖,請對照原卷】
圖2: AVL tree。

🖼️ 本題含圖表,以下為原卷對應頁面:
原卷第 3 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

本題考查 AVL tree 的兩項操作:

  1. 插入節點後,利用平衡因子判斷是否失衡,並進行旋轉。
  2. 刪除節點後,重新計算各祖先節點的平衡因子,必要時進行旋轉。

平衡因子定義為:

BF(v)=高度(左子樹)−高度(右子樹)BF(v)=高度(左子樹)-高度(右子樹)

AVL tree 必須滿足:

BF(v)∈{−1,0,1}BF(v)\in\{-1,0,1\}

題目資訊不足

目前附上的圖片是「控制系統」考題第 2 頁,圖中沒有本題所需的「圖 2 AVL tree」。因此無法得知原始 AVL tree 的節點配置,也就無法唯一確定插入 7373 及刪除 2828 後的兩棵樹。

解題方法

① 插入 7373

依照二元搜尋樹規則,從根節點開始比較:

  • 7373 大於目前節點,往右子樹走。
  • 7373 小於目前節點,往左子樹走。
  • 找到空位置後插入葉節點 7373。

接著由插入位置向根節點回溯,更新高度並計算每個祖先的平衡因子。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

第 5 題10 分

圖 3 為「雙向環狀串列(doubly circular linked list,或者簡稱 doubly circular list)」的資料結構範例,其中每個 Node 的結構包含三個欄位「prev、data、next」。更具體地說,Node 的結構宣告如下:

struct Node {
Node* prev; // 指向前一個 Node
int data; // 用來儲存整數型別的資料
Node* next; // 指向下一個 Node
};

🖼️【此處有附圖,請對照原卷】

為了實現雙向環狀串列,我們用 C++ 程式語言宣告一個類別(class),如下:

class DoublyCircularList {
private:
int numberOfNodes; // 紀錄雙向環狀串列裡頭的 Node 數量
Node* head; // 此一指標變數永遠指向雙向環狀串列裡頭的第一個 Node
Node* tail; // 此一指標變數永遠指向雙向環狀串列裡頭的最後一個 Node

public:
DoublyCircularList() { // 此為預設建構式(default constructor)
numberOfNodes = 0;
head = tail = nullptr;

    // nullptr 是 C++ 的關鍵字,是 null pointer 的意思
}

// 其餘省略

};

DoublyCircularList 類別裡頭包含二個指標變數:head 和 tail。如圖 3 所示,指標變數 head 永遠指向串列裡頭的第一個 Node,指標變數 tail 永遠指向串列裡頭的最後一個 Node。

請幫 DoublyCircularList 類別撰寫一個成員函式(member function),其宣告為 void removeFrontNode(),其功能是將 head 指標變數所指到的 Node 刪除。

注意:此題限定使用 C++ 程式語言撰寫成員函式,使用其他程式語言或 pseudo code,將酌情扣分。

🖼️ 本題含圖表,以下為原卷對應頁面:
原卷第 3 頁原卷第 4 頁

登入後即可作答並保存紀錄。

這一題的完整詳解

核心觀念

雙向環狀串列的每個節點都有 prev 與 next 指標。若串列非空,首尾相接:head->prev 指向 tail,tail->next 指向 head。刪除頭節點時,要更新新頭節點、尾節點的環狀連結,並釋放舊頭節點的記憶體。

解題方法

圖 3 中節點依序為 31 → 25 → 79 → 64,head 指向 31,tail 指向 64;環狀連結為 64.next = 31、31.prev = 64。刪除 head 時,分別處理空串列、只有一個節點,以及至少兩個節點的情況。

🔒

後續完整解題步驟與【答案】

免費註冊,享三天全站完整詳解閱覽。

免費註冊

其他考古題