# 2021q1 Homework1 (quiz1)
contributed by < `Jings1017` >
###### tags: `linux2021`
> [測驗題](https://hackmd.io/@sysprog/linux2021-quiz1)
## 解析
### node 結構定義
```c
typedef struct __node{
int value;
struct __node *next;
} node_t
```
此題所定義的 node 結構及連接方式如下圖所示
```graphviz
digraph SLL{
rankdir = LR
head [shape=record, label="head"]
node1 [shape=record, label="{A|{<value>value}|<next>next}"];
node2 [shape=record, label="{B|{<value>value}|<next>next}"];
head:e -> node1:w;
node1:next:e-> node2:w;
}
```
### list_add_node_t
```cpp
static inline void list_add_node_t(node_t **list, node_t *node_t) {
node_t->next = *list;
*list = node_t;
}
```
下圖中, node_t 為欲插入的新節點,
首先將 list 整個接到 node_t 之後方,
再把 node_t 令為新串列之 head (紅色 head )
```graphviz
digraph structs{
rankdir=LR;
node[shape=box];
node1[label=node_t color=red];
{
head0[label="head" shape=plaintext,fontcolor=blue]
head1[label="head" shape=plaintext,fontcolor=red]
list0[label=A];
list1[label=B];
list2[label=C];
}
{
rank="same"
head0->list0
}
{
rank = "same"
head1->node1
}
node1->list0->list1->list2
}
```
### list_concat
```cpp
static inline void list_concat(node_t **left, node_t *right) {
while (*left)
left = &((*left)->next);
*left = right;
}
```
這一部份的程式碼主要是先找到 list 最後一個 node 的 next,再將 *left 指向上述之位置
```graphviz
digraph structs {
rankdir=LR;
node[shape=box];
left[label= "*left" shape= plaintext, fontcolor=blue];
null[label= "NULL" shape= plaintext];
n1[label= "a1"];
n2[label= "a2"];
n3[label= "a3"];
{
rank="same";
left->null;
}
n1->n2->n3->null;
}
```
最後再把 *left 指向 right,如此一來就可將 left 與 right 串連在一起
```graphviz
digraph structs {
rankdir=LR;
node[shape=box];
left[label= "*left" shape= plaintext, fontcolor=blue];
l1[label= "a1"];
l2[label= "a2"];
l3[label= "a3"];
r1[label= "b1" color=red];
r2[label= "b2" color=red];
{
rank="same";
left->r1;
}
l1->l2->l3->r1->r2;
}
```
### quicksort
```cpp
void quicksort(node_t **list)
{
if (!*list)
return;
node_t *pivot = *list;
int value = pivot->value;
node_t *p = pivot->next;
pivot->next = NULL;
node_t *left = NULL, *right = NULL;
while (p) {
node_t *n = p;
p = p->next;
list_add_node_t(n->value > value ? AAA : BBB, n);
}
quicksort(&left);
quicksort(&right);
node_t *result = NULL;
list_concat(&result, left);
CCC;
*list = result;
}
```
### AAA = ? / BBB = ?
&right / &left
根據 `list_add_node_t(n->value > value ? AAA : BBB, n); ` 可知若目前的 value 大於 pivot 之值,則放入 right ,反之,若小於 piovt 之值,則放入 left 。
又因為 list_add_node_t() 函式中使用 node_t ** ,故 `AAA = &right` , `BBB = &left`
### CCC = ?
list_concat(&result, pivot);
list_concat(&result, right);
在此處主要是做串接,由左到右的順序為 left, pivot, right , 故在此填入 `list_concat(&result, pivot);`, `list_concat(&result, right);`
## 延伸問題
### Non-Recursive Quick Sort
參考 [Optimized QuickSort](https://alienryderflex.com/quicksort/) 實作 non-recursive quick sort
想法是先選定 pivot ,這裡用最左方的元素當作 pivot ,
然後 L, R 是欲排序的範圍,其中 L 表最左,R 表最右,
用 pivot 和此範圍中每個元素比較。
若從 R 往左開始,比 pivot 小的 放到 arr[L],再做 L++,
若從 L 往左開始,比 pivot 大的 放到 arr[R],再做 R++
![](https://i.imgur.com/Fi4JumR.png)
#### 程式碼 A
```cpp
void quicksort_NR(node_t **list){
/* put list in the arr */
node_t *ptr = *list;
int arr[NUM_SIZE], cnt=0;
while(ptr){
arr[cnt++] = ptr->value;
ptr = ptr->next;
}
free(ptr);
int pivot, L, R;
int beg[NUM_SIZE], end[NUM_SIZE];
cnt = 0;
beg[0] = 0;
end[0] = NUM_SIZE;
while(cnt>=0){
L = beg[cnt];
R = end[cnt]-1;
if(L<R){
pivot = arr[L];
if(cnt == NUM_SIZE-1)
return ;
while(L<R){
while(arr[R] >= pivot && L<R){
R--;
}
if(L<R){
arr[L++] = arr[R];
}
while(arr[L] <= pivot && L<R){
L++;
}
if(L<R){
arr[R--] = arr[L];
}
}
arr[L] = pivot;
int tmp = end[cnt];
end[cnt] = L;
cnt++;
beg[cnt] = L+1;
end[cnt] = tmp;
}
else{
cnt--;
}
}
/* update the list */
node_t *pointer = *list;
cnt = 0;
while(pointer){
pointer->value = arr[cnt++];
pointer = pointer->next;
}
free(pointer);
}
```