# 2021q1 Homework2 (quiz2) contributed by < [bobhsiao0306](https://github.com/bobhsiao0306) > > [GitHub repository](https://github.com/bobhsiao0306/linux2021_quiz2) ###### tags: `linux2021` `quiz2` ## 測驗 1 在 main() 函式中,首先先將 `cities.txt` 中讀到的每一行利用 ==q_insert_head== 新增至 queue 的頂端 ### q_insert_head ```cpp= bool q_insert_head(queue_t *q, char *s) { if (!q) return false; list_ele_t *newh = malloc(sizeof(list_ele_t)); if (!newh) return false; char *new_value = strdup(s); if (!new_value) { free(newh); return false; } newh->value = new_value; newh->next = q->head; q->head = newh; if (q->size == 0) q->tail = newh; q->size++; list_add_tail(&newh->list, &q->list); return true; } ``` 而 ==q_insert_head== 則是利用 ==list_add_tail== 新增的節點加入 doubly linked list 的尾端 ### list_add_tail ```graphviz digraph { rankdir=LR node [shape="box"] edge [dir="both"] left [label="..." shape="none"] pnode [label="head->prev"] nnode [label="new node", color="red"] head [label="head"] right [label="..." shape="none"] left -> pnode pnode -> head [color=gray, style=dashed] head -> right pnode -> nnode -> head [color=red] } ``` > 紅色實線為新增的連結及節點,灰色虛線則為刪除的連結 ### Merge Sort ![](https://i.imgur.com/ST55FE2.png) 接下來對先前的 doubly linked list 做 merge sort,分為三個部份 * ==list_cut_position== 函式中利用 ==get_middle== 將 doubly linked list 切成左右兩半 * 遞迴呼叫 ==list_merge_sort== * ==list_merge== 將左右兩半排序好的 linked list 合併起來 #### get_middle ```cpp= static list_ele_t *get_middle(struct list_head *list) { struct list_head *fast = list->next, *slow; list_for_each (slow, list) { if (fast->next == list || fast->next->next == list) break; fast = fast->next->next; } return list_entry(slow, list_ele_t, list); } ``` slow 一次前進一個節點,fast 一次前進兩個節點,而當 fast 前進至倒數第一個或倒數第二個節點時,slow 剛好會在 linked list 的中間節點 :::warning TODO: 討論切分 list 的適當位置及比例 :notes: jserv ::: #### `list_cut_position` 輸入為一個 doubly linked list ```graphviz digraph { rankdir=LR node [shape="box"] edge [dir="both"] head_from[label="q->list", color="red"] head_from_first[label="q->list->next", color="blue"] left [label="..." shape="none"] node_prev [label="slow->prev", color="blue"] nnode [label="slow", color="blue"] node_next [label="slow->next", color="red"] tail [label="tail", color="red"] right [label="..." shape="none"] head_from -> head_from_first -> left -> node_prev -> nnode -> node_next -> right -> tail -> head_from } ``` 經過 ==list_cut_position== 後切成兩個 doubly linked list ```graphviz digraph { rankdir=LR node [shape="box"] edge [dir="both"] head_to[label="left.list", color="blue"] head_from[label="q->list", color="red"] head_from_first[label="q->list->next", color="blue"] left [label="..." shape="none"] node_prev [label="slow->prev", color="blue"] nnode [label="slow", color="blue"] node_next [label="slow->next", color="red"] tail [label="tail", color="red"] right [label="..." shape="none"] head_from -> node_next nnode -> head_to -> head_from_first head_from_first -> left -> node_prev -> nnode node_next -> right -> tail -> head_from } ``` ## 測驗 2 函式 func 接受一個 16 位元無號整數 N,並回傳小於或等於 N 的 power-of-2 ```cpp= uint16_t func(uint16_t N) { /* change all right side bits to 1 */ N |= N >> 1; N |= N >> 2; N |= N >> 4; N |= N >> 8; return (N + 1) >> 1; } ``` ### 作法 1. 無號數N的二進位表示法中(e.g. 00101000),使最左邊的1其右側的 bits 都變成1(e.g. 00111111),而將N與自己右移1 bit、2 bit、4 bit、8 bit 做 or 運算即可達到此效果。 2. 加1之後再右移1 bit 即可得到小於或等於 N 的 power-of-2。