# 2020q1 Homework3 (quiz3) contributed by < `jwang0306` > > [作業要求](https://hackmd.io/@sysprog/rJXs6hrHU) ## 測驗一: XOR Linked List 題目的敘述有一段 `insert_node` 的程式碼: ```cpp void insert_node(list **l, int d) { list *tmp = malloc(sizeof(list)); tmp->data = d; if (!(*l)) { tmp->addr = NULL; } else { (*l)->addr = XOR(tmp, (*l)->addr); tmp->addr = *l; } *l = tmp; } ``` 上課時我被問到這個是插在 list 的頭還是尾巴,印象中我只有回答其中一個,但是後來仔細思忖,答案是頭尾都可以,端看參數 `list **l` 給的是頭還是尾。 已知 XOR 的運算特性: * $A \oplus 0 = A$ * $(A \oplus B) \oplus B = A$ 走訪 list 的方式為當前節點與前一個節點取 XOR ,假設節點 1, 2, 3, 4 ,當前節點在 1 : ``` 1 2 3 4 data HAT CAT EAT BAT ``` - 要走到 2 的話,就是 `link(1) XOR 0` = `(0 XOR 2) XOR 0` = `2` (根據特性二) - 要插入一個 `FAT` 到尾巴的話,如果 list 為空,直接 `*l = tmp` ,前後都沒人因此 `addr` 為 `NULL` - 如果 list 不為空 - 我們希望插入後的 l 其位置為 `link(4) XOR 0` ,因此取 `XOR(tmp, (*l)->addr);` , `0 XOR link(4)` = `link(4)` (根據特性一),然後將其更新為 `l` 的當前 `addr` ,這樣就清出了一個新的空間 - 最後再把 `tmp` 放進去 - 插在頭也是一樣的 ## 解釋下方 XOR linked list 排序實作的原理 ```cpp list *sort(list *start) { if (!start || !start->addr) return start; /* split the list recursively */ list *left = start, *right = start->addr; left->addr = NULL; right->addr = XOR(right->addr, left); left = sort(left); right = sort(right); /* merge the list recursively */ for (list *merge = NULL; left || right;) { if (!right || (left && left->data < right->data)) { list *next = left->addr; if (next) next->addr = XOR(left, next->addr); if (!merge) { start = merge = left; merge->addr = NULL; } else { merge->addr = XOR(merge->addr, left); left->addr = merge; merge = left; } left = next; } else { list *next = right->addr; if (next) next->addr = XOR(right, next->addr); if (!merge) { start = merge = right; merge->addr = merge; } else { merge->addr = XOR(merge->addr, right); right->addr = RR2; merge = right; } right = next; } } return start; } ``` 上述的 XOR linked-list 用了類似 merge sort 的手法,不斷地切割 list ,最後拼裝起來: - 先讓 `next` 走向下一個節點 - 首次進入迴圈, `merge` 為空,因此根據大小設定為 `left` 或 `right` ,`addr` 為 `NULL` - 否則將 `left` 接上(假設為 `left` ), 與上述走訪的概念一樣, `merge->addr = XOR(merge->addr, left);` (`merge` 就像上方 `insert_node` 的 `l`) ,並將 `left->addr` 更新為 `0 XOR mege` 也就是 `merge` (根據特性一),最後將 `left` 放進 `merge`