# 2024q1 Homework2 (quiz1+2)
contributed by < `LIAO-JIAN-PENG` >
## 第一週測驗題
### 測驗一
#### shuffle
```c
/* shuffle array, only work if n < RAND_MAX */
void shuffle(int *array, size_t n)
{
if (n <= 0)
return;
for (size_t i = 0; i < n - 1; i++) {
size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
int t = array[j];
array[j] = array[i];
array[i] = t;
}
}
```
在 rand() 函式中,它生成的隨機數的範圍是 0 到 RAND_MAX。然而,我們需要的是一個介於 i 到 n-1 之間的隨機整數。
一種方法是將 rand() 函式生成的隨機數除以 (RAND_MAX / (n - i) + 1)。這樣可以得到一個介於 0 到 (n - i) - 1 之間的隨機整數。然後,我們將這個值加上 i,這樣就可以得到介於 i 到 n-1 之間的隨機整數。添加 1 的目的是確保 (n - i) 不為 0,以避免除法計算可能導致的錯誤。
> C 語言規格書 7.22.2.1
> The rand function computes a sequence of pseudo-random integers in the range 0 to RAND_MAX.
#### 非遞迴快速排序法
這段程式碼使用了 [Optimized QuickSort — C Implementation (Non-Recursive)](https://alienryderflex.com/quicksort/) 非遞迴快速排序法。在這個算法中,我們使用 `L` 和 `R` 來記錄待排序部分的起始和結束位置。首先,我們將 `L` 設置為 `pivot`,然後通過 `n` 和 `p` 遍歷後面的節點。將小於 `pivot->value` 的節點放入 `left`,將大於 `pivot->value` 的節點放入 `right`。這些節點以後進先出(LIFO)的方式被存入,以相反的順序記錄著節點。以 `3, 1, 2, 4, 5` 做舉例
```graphviz
digraph {
"pivot"[shape=box]
"L"[shape=box]
"R"[shape=box]
3[shape=box]
1[shape=box]
2[shape=box]
4[shape=box]
5[shape=box]
pivot->3
{rank=same 3 1 2 4 5}
L->3->1->2->4->5
R->5
p->1
}
```
---
```graphviz
digraph {
"left"[shape=box]
"right"[shape=box]
"pivot"[shape=box]
3[shape=box]
1[shape=box]
2[shape=box]
4[shape=box]
5[shape=box]
pivot->3
left->2->1
right->5->4
}
```
---
```graphviz
digraph {
"begin[i]"[shape=box]
"begin[i+1]"[shape=box]
"begin[i+2]"[shape=box]
"end[i]"[shape=box]
"end[i+1]"[shape=box]
"end[i+2]"[shape=box]
3[shape=box]
1[shape=box]
2[shape=box]
4[shape=box]
5[shape=box]
"begin[i]"->2->1
"begin[i+1]"->3
"begin[i+2]"->5->4
"end[i]"->1
"end[i+1]"->3
"end[i+2]"->4
}
```
在這個過程中,我們使用 `begin[i]` 和 `end[i]` 來分別記錄 `left` 部分的開始和結束位置,使用 `begin[i+1]` 和 `end[i+1]` 來記錄 `pivot`,以及使用 `begin[i+2]` 和 `end[i+2]` 來記錄 `right` 部分的開始和結束位置。每次循環中 `i+=2` 表示我們下一次迭代將針對 `right` 部分進行排序。
當 `L` 等於 `R` 時,這表示我們只剩下一個節點,我們將排序結果放入 `result` 中。
```graphviz
digraph {
"L"[shape=box]
"R"[shape=box]
3[shape=box]
L->3
R->3
}
```
當 `L` 不等於 `R` 時,我們仍然可以將其分成 `left` 和 `right` 兩部分進行操作。
```graphviz
digraph {
"L"[shape=box]
"R"[shape=box]
5[shape=box]
4[shape=box]
L->5->4
R->4
}
```