# 2021q1 Homework1 (quiz1)
contributed by < shanlee870502 >
###### tags: `linux2021`
> [第 1 週測驗題](https://hackmd.io/@sysprog/linux2021-quiz1)
### QuickSort 運作原理:
使用 Divide and Conquer 的概念,每次迭帶選一個 pivot,比 pivot 大的放右邊,比 pivot 小的放左邊,而左、右各成一新數列,繼續迭帶,直到數列無法分割,即完成排序。
* code:
```c=
static inline void list_add_node_t(node_t **list, node_t *node_t){
node_t->next = *list;
*list - node_t;
}
static inline void list_concat(node_t **left, node_t *right){
while(*left){
left = &((*left)->next);
}
*left = right;
}
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 ? &right:&left, n);
}
quicksort(&left);
quicksort(&right);
node_t *result = NULL;
list_concat(&result, left);
list_concat(&result, pivot);
list_concat(&result, right);
*list = result;
}
```
* 圖解:
進入while迴圈前:
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
n1 [label="{ <data> 2 | <ref> }"];
n2 [label="{ <data> 5 | <ref> }"];
n3 [label="{ <data> 3 | <ref> }"];
n4 [label="{ <data> 6 | <ref> }"];
n5 [label="{ <data> 4 | <ref> }"];
n6 [label="{ <data> 1 | <ref> }"];
NULL_1[label=NULL,shape=plaintext];
NULL_2[label=NULL,shape=plaintext];
NULL_3[label=NULL,shape=plaintext];
NULL_4[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
pivot[shape="none", label = "pivot", fontcolor="blue"];
p[shape="none", label = "p", fontcolor="blue"];
}
//link operation
{
n1:ref:c -> NULL_1:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n2:ref:c -> n3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n3:ref:c -> n4:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n4:ref:c -> n5:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n5:ref:c -> n6:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n6:ref:c -> NULL_2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
pivot->n1;
p->n2;
left->NULL_3;
right->NULL_4;
// right->r1
// head->l1
// left->right
// ptr->l3
}
}
```
---
whlie迴圈(比pivot值小的放左邊,大的放右):
```
node_t *n = p
p=p->next
```
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
n1 [label="{ <data> 2 | <ref> }"];
n2 [label="{ <data> 5 | <ref> }"];
n3 [label="{ <data> 3 | <ref> }"];
n4 [label="{ <data> 6 | <ref> }"];
n5 [label="{ <data> 4 | <ref> }"];
n6 [label="{ <data> 1 | <ref> }"];
NULL_1[label=NULL,shape=plaintext];
NULL_2[label=NULL,shape=plaintext];
NULL_3[label=NULL,shape=plaintext];
NULL_4[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
pivot[shape="none", label = "pivot", fontcolor="blue"];
p[shape="none", label = "p", fontcolor="blue"];
n[shape="none", label = "n", fontcolor="blue"];
}
//link operation
{
n1:ref:c -> NULL_1:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n2:ref:c -> n3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n3:ref:c -> n4:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n4:ref:c -> n5:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n5:ref:c -> n6:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n6:ref:c -> NULL_2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
pivot->n1;
p->n3;
n->n2;
left->NULL_3;
right->NULL_4;
// right->r1
// head->l1
// left->right
// ptr->l3
}
}
```
```list_add_node_t(n->value > value ? &right: &left, n);```
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
n1 [label="{ <data> 2 | <ref> }"];
n2 [label="{ <data> 5 | <ref> }"];
n3 [label="{ <data> 3 | <ref> }"];
n4 [label="{ <data> 6 | <ref> }"];
n5 [label="{ <data> 4 | <ref> }"];
n6 [label="{ <data> 1 | <ref> }"];
NULL_1[label=NULL,shape=plaintext];
NULL_2[label=NULL,shape=plaintext];
NULL_3[label=NULL,shape=plaintext];
NULL_4[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
pivot[shape="none", label = "pivot", fontcolor="blue"];
p[shape="none", label = "p", fontcolor="blue"];
n[shape="none", label = "n", fontcolor="blue"];
}
//link operation
{
n1:ref:c -> NULL_1:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n3:ref:c -> n4:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n4:ref:c -> n5:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n5:ref:c -> n6:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
n6:ref:c -> NULL_2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
pivot->n1;
p->n3;
n->n2;
left->NULL_3;
n2->NULL_4;
right->n2;
}
{
rank="same"
}
}
```
跳出while迴圈之後,應會分割為兩 sublist : 4->6->3->5 以及 1 (分別為比 pivot value 大的以及比 pivot value 小的兩串列),之後再遞迴兩個sublist作上述圖解的分割,最後用 ```list_concat```把 sublist 接起來。
### 函式
#### list_add_node_t
* 將一個 ```node_t``` 節點加在 ```*list``` 前方,且讓 ```*list```指向串列最前端(也就是 ```node_t``` )
```c=
static_inline void list_add_node_t(node_t **list, node_t *node_t){
node_t -> next = *list;
*list = node_t;
}
```
* 圖解:
假設傳入 ```list_add_node_t```之狀態如下(藍色:指標,紅色:指標的指標):
``` graphviz
digraph foo {
rankdir = LR;
node[shape=record];
list[shape="none", label = "list", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
node_t [label="{ <data> node_t | <ref> }"];
a [label="{ <data> 4 | <ref> }"];
b [label="{ <data> 5 | <ref> }"];
c [label="{ <data> 6 | <ref> }"];
NULL[label=NULL,shape=plaintext];
NULL2[label=NULL,shape=plaintext];
a:ref:c -> b:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
b:ref:c -> c:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
c:ref:c -> NULL:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
node_t:ref:c -> NULL2:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
ptr->node_t
list-> head
head-> a
}
```
```node_t -> next = *list```
``` graphviz
digraph foo {
rankdir = LR;
node[shape=record];
list[shape="none", label = "list", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
node_t [label="{ <data> node_t | <ref> }"];
a [label="{ <data> 4 | <ref> }"];
b [label="{ <data> 5 | <ref> }"];
c [label="{ <data> 6 | <ref> }"];
NULL[label=NULL,shape=plaintext];
a:ref:c -> b:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
b:ref:c -> c:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
c:ref:c -> NULL:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
ptr->node_t
node_t -> a
list-> head
head->a
}
```
```*list = node_t```
``` graphviz
digraph foo {
rankdir = LR;
node[shape=record];
list[shape="none", label = "list", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
node_t [label="{ <data> node_t | <ref> }"];
a [label="{ <data> 4 | <ref> }"];
b [label="{ <data> 5 | <ref> }"];
c [label="{ <data> 6 | <ref> }"];
NULL[label=NULL,shape=plaintext];
a:ref:c -> b:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
b:ref:c -> c:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
c:ref:c -> NULL:data [arrowhead=vee, arrowtail=dot, dir=both, tailclip=false]
ptr->node_t
node_t -> a
list-> ptr
head->a
}
```
#### list_concat
* 連接兩條 list,由 while 迴圈找到 ```left``` 串列的最尾端( NULL ),再將其指向 ```right```的開頭
```c=
static inline void list_concat(node_t **left, node_t *right) {
while (*left)
left = &((*left)->next);;
*left = right;
}
```
* 圖解:
假設傳入 ```list_concat```之狀態如下:
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
r1 [label="{ <data> 1 | <ref> }"];
r2 [label="{ <data> 2 | <ref> }"];
r3 [label="{ <data> 3 | <ref> }"];
l1 [label="{ <data> 4 | <ref> }"];
l2 [label="{ <data> 5 | <ref> }"];
l3 [label="{ <data> 6 | <ref> }"];
NULL_l[label=NULL,shape=plaintext];
NULL_r[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
ptr_next[shape="none", label = "ptr->next", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
}
//link operation
{
l1:ref:c -> l2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l2:ref:c -> l3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l3:ref:c -> NULL_l:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r1:ref:c -> r2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r2:ref:c -> r3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r3:ref:c -> NULL_r:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
right->r1
head->l1
left->head
ptr->l3
ptr_next->NULL_l
}
}
```
while迴圈:
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
r1 [label="{ <data> 1 | <ref> }"];
r2 [label="{ <data> 2 | <ref> }"];
r3 [label="{ <data> 3 | <ref> }"];
l1 [label="{ <data> 4 | <ref> }"];
l2 [label="{ <data> 5 | <ref> }"];
l3 [label="{ <data> 6 | <ref> }"];
NULL_l[label=NULL,shape=plaintext];
NULL_r[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
ptr_next[shape="none", label = "ptr->next", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
}
//link operation
{
l1:ref:c -> l2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l2:ref:c -> l3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l3:ref:c -> NULL_l:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r1:ref:c -> r2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r2:ref:c -> r3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r3:ref:c -> NULL_r:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
right->r1
head->l1
left->ptr_next
ptr->l3
ptr_next->NULL_l
}
}
```
```*left = right;```
```graphviz
digraph foo {
rankdir = LR;
node[shape=record];
//node declaration
{
r1 [label="{ <data> 1 | <ref> }"];
r2 [label="{ <data> 2 | <ref> }"];
r3 [label="{ <data> 3 | <ref> }"];
l1 [label="{ <data> 4 | <ref> }"];
l2 [label="{ <data> 5 | <ref> }"];
l3 [label="{ <data> 6 | <ref> }"];
NULL_r[label=NULL,shape=plaintext];
}
//pointer declaration (including pointer to pointer)
{
left[shape="none", label = "left", fontcolor="red"];
head[shape="none", label = "head", fontcolor="blue"];
ptr[shape="none", label = "ptr", fontcolor="blue"];
right[shape="none", label = "right", fontcolor="blue"];
}
//link operation
{
l1:ref:c -> l2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l2:ref:c -> l3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
l3:ref:c -> r1:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r1:ref:c -> r2:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r2:ref:c -> r3:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
r3:ref:c -> NULL_r:data [arrowhead=vee, arrowtail=dot, dir=both , tailclip=false]
}
//pointer operation
{
right->r1
head->l1
left->right
ptr->l3
}
}
```
### random 修正
* random 函式產生亂數非亂數!(多次執行發現仍相同)。
* 使用srand()產生亂數種子
* 程式片段說明(改變第6行):
```c=
int main(int argc, char **argv) {
size_t count = 20;
node_t *list = NULL;
srand((unsigned) time(&t));
while (count--)
list = list_make_node_t(list, random() % 1024);
list_display(list);
quicksort(&list);
list_display(list);
if (!list_is_ordered(list))
return EXIT_FAILURE;
list_free(&list);
return EXIT_SUCCESS;
}
```
### 避免使用遞迴呼叫的QuickSort
> [Optimized QuickSort](https://alienryderflex.com/quicksort/)
* 概念:
* code:
//TODO