# 2024q1 Homework2 (quiz1+2)
contributed by < [`Randy-Chuang`](https://github.com/Randy-Chuang) >
## 2024q1 [第 1 週測驗題](https://hackmd.io/@sysprog/linux2024-quiz1)
### 測驗 `1`
先參考 [Optimized QuickSort — C Implementation (Non-Recursive)](https://alienryderflex.com/quicksort/) ,以下我把程式碼片段貼入解釋理解過程:
```c 
    i = 0; beg[0]=0; end[0]=elements;
    while (i>=0) {
        L=beg[i]; R=end[i]-1;
        if (L<R) {
            // 取區段 (partition) 第一個 element 做 pivot 來比較
            piv=arr[L]; if (i==MAX_LEVELS-1) return NO;
            while (L<R) {
                /// 從區段頭尾比較,根據 pivot 將區段分為小大兩邊
                while (arr[R]>=piv && L<R) R--; if (L<R) arr[L++]=arr[R]; 
                while (arr[L]<=piv && L<R) L++; if (L<R) arr[R--]=arr[L]; 
            }
            // 將區端分為小大兩個子區段
            arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L; 
        } else {
            i--; // L < R 代表區段排序尚未結束,持續減少讓迴圈運作到結束
        }
    }
```
範例顯示外層迴圈第一輪結束後的結果:

外層迴圈跑完第一輪陣列 `beg[]` 和 `end[]` 內數值的變化:
| 陣列 \ index | 0                 | 1                 | 2   | ... |
| ------------ | ----------------- | ----------------- | --- | --- |
| `beg[]`      | 0 $\rightarrow$ 0 | 0 $\rightarrow$ 4 | 0   | 0   |
| `end[]`      | 8 $\rightarrow$ 3 | 0 $\rightarrow$ 8 | 0   | 0   |
配上範例能發現排序過程中 pivot 變數被用來將大小區段分開後,再改變 `beg[]` 和 `end[]` 來紀錄目前 Quick Sort 待排序的區段,以每次迴圈迭代而更改的陣列內容當作分枝來看,就能看出 Quick Sort 遞迴樹的變化,行為與 [Iterative DFS](https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search) 中佇列的控制相同。每跑一次迴圈,當次選用的 pivot 就會被擺到左區塊最後,因此左邊區段最後的元素剛好不用再排序 (圖中紅色標示) 。
```graphviz
digraph g {
    label="Quick Sort Recursion Tree";
    node [shape = record,height=.1];
    node0[label = "[0, 8)"];
    node1[label = <[0, <FONT COLOR="red">3</FONT>)>];
    node2[label = "[4, 8)"];
    node3[label = ""];
    node4[label = ""];
    node5[label = ""];
    node6[label = ""];
    "node0" -> "node1";
    "node0" -> "node2";
    "node1" -> "node3";
    "node1" -> "node4";
    "node2" -> "node5";
    "node2" -> "node6";
}
```
但是待排序陣列若是排列特殊會讓遞迴樹產生傾斜,極端情況會讓分配不均的小區段一直保留在 `beg[]` 和 `end[]` 陣列前端,造成長度不足以紀錄遞迴樹的分枝,因此作者改善程式碼確保迭代過程中優先處理較小的區段,遞迴樹的高度不會超過 $\lceil {Log_2(n)} \rceil$ 。
```graphviz
digraph g {
    label="Quick Sort Tilted Recursion Tree";
    node [shape = record,height=.1];
    node0[label = "[0, n)"];
    node1[label = "[0, 1)"];
    node2[label = "[2, n)"];
    node3[label = "..."];
    node4[label = "..."];
    node5[label = "[2, 3)"];
    node6[label = "[4, n)"];
    node7[label = "[6, n)"];
    node8[label = "[8, n)"];
    "node0" -> "node1";
    "node0" -> "node2";
    "node2" -> "node5";
    "node2" -> "node6";
    "node6" -> "node7";
    "node6" -> "node3";
    "node7" -> "node8";
    "node7" -> "node4";
}
```
```diff 
            arr[L]=piv; beg[i+1]=L+1; end[i+1]=end[i]; end[i++]=L; 
+           if (end[i]-beg[i] > end[i-1]-beg[i-1]) {
+               swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
+               swap=end[i]; end[i]=end[i-1]; end[i-1]=swap; 
+           }
        } else {
            i--; 
        }
```
#### 測驗程式碼
(*left)->next
(*left)->next
p->next
list_tail(&left)
list_tail(&right)
:::warning
延伸問題:
解釋上述程式碼的運作原理,提出改進方案並予以實作。
使用 Linux 核心風格的 List API 改寫上述程式碼,並針對鏈結串列,提出可避免最差狀況的快速排序實作,應設計效能評比的測試程式。
:::
### 測驗 `2`
:::warning
延伸問題:
解釋上述程式碼的運作原理,提出改進方案並予以實作。
將改進過的 Timsort 實作整合進 sysprog21/lab0-c,作為另一個有效的排序命令,應設計效能評比的測試程式,確保測試案例符合 Timsort 設想的資料分布樣式。
:::
## 2024q1 [第 2 週測驗題](https://hackmd.io/@sysprog/linux2024-quiz2)
### 測驗 `1`
### 測驗 `2`
### 測驗 `3`
## 表單測驗
## 參考資料
- Graphviz 
    - [Graphviz Doc](https://graphviz.org/documentation/) / [Layout Engines](https://graphviz.org/docs/layouts/) / [Gallery](https://www.graphviz.org/gallery/) / [Drawing graphs with dot](https://graphviz.org/pdf/dotguide.pdf)
    - [Multiple graphs inside Graphviz DOT file](https://stackoverflow.com/questions/63869676/multiple-graphs-inside-graphviz-dot-file)