contributed by < kylekylehaha
>
linux2020
XOR Linked list
根據維基百科的描述 XOR linked list
An XOR linked list is a type of data structure used in computer programming. It takes advantage of the bitwise XOR operation to decrease storage requirements for doubly linked lists.
意思是說 XOR linked list
可以達到 doubly linked list
的效果:可以在 O(1) 的時間複雜度下,取得前一項和後一項
,然而 XOR linked list
的空間雜度可以比 doubly linked list
低,因為只需要一個指標,而 doubly linked list
卻需要兩個指標 prev
& next
。
如何使用 XOR linked list
呢?
公式: address of next node = address of perv node ^ pointer in the current node.
,其中我們將 address of next node
記作 addr(next)
; address of perv node
記作 addr(prev)
我們套入三種 case 來證明:
0 ^ addr(next)
= addr(next)
NULL
addr(prev) ^ 0
= addr(prev)
測驗一題目:
可以發現,這題和第一週題目相似,都是實做 merge sort
。
LL1
& LL2
left
為 head,因此 left->addr
即為它的下一個 nodemerge
為 merge list 的 tail,故我們要將 left
的 head 插在 merge
後面,並更新 merge->addr
。在更新前, merge->addr
= addr(prev)
merge
所指的記憶體位置,我們用 merge'
代替。此時 merge'->addr
應為 addr(prev) ^ addr(next)
= addr(prev) ^ addr(left)
,在之前我們已知 addr(prev)
= merge->addr
; left
插在 merge'
後面。LL1
= XOR(merge->addr, left)
。left
為 tail ,故其 left->addr
存的是上一個 node,也就是 merge
。故 LL2
= merge
RR1
& RR2
由於兩者對稱,因此我們可知 RR1
= XOR(merge->addr, right)
, RR2 = merge
這邊的排序,基本上就是 merge sort。然而因為 left
只有一個節點,故 merge sort
效果不佳,會退化成 insertion sort,因此我們可以參考 lab0 的做法,將 split
加到 sort
:從中間開始切。
For example, the tiled merge sort algorithm stops partitioning subarrays when subarrays of size S are reached, where S is the number of data items fitting into a CPU's cache
insertion_sort
來當作 optimizing merge sort 的 in-place algo.print
, insertion_sort
和 op_merge_sort
print()
data
印出來,方便 debug。insertion_sort
sorted
& 尚未排序的序列,每次都將尚未排序的序列取一個出來,和 sorted
一起丟入 merge
內做排序。Optimizing merge sort
S
時,我們使用 insertion_sort
; 大於 s
時則繼續遞迴 op_merge_sort
split
用來平均切割序列,切割成兩個長度相同或是長度相差 1 的 子序列。利用實驗找出 threshold S
LIST_LEN
長度拉長,可以比較明顯看出 op_merge_sort
的效果。S
的範圍從 0 ~ 1000 ,可以清楚發現有四個階段lstopo
命令來看出自己 cpu 的架構。須先安裝套件:
$ sudo apt-get install hwloc
threshold
小於 150 左右時,op_merge_sort
效果較佳。比較 insertion_sort
, merge_sort
和 op_merge_sort
insertion_sort
, merge_sort
和 op_merge_sort
,比較三者的時間。實驗結果討論
op_merge_sort
最佳,insertion_sort
最差,這和預期的結果符合。rand()%100
,也就是說在 random 的情況下,insertion_sort
不太會出現 worst case,也就是遞減的順序,因此其時間沒有差太多。基本上,這題就是 Linus Torvald 在 TED 演講所提到的「有品味的程式碼」,可以參照 fcamel 的心得。我們直接來看問題:
可透過以下 pointer to pointer 改寫 insert 函式,功能等價但更簡潔,如下:
兩者差別
解題思路
AA
link
是 pointer to pointer,因此必須先 dereference 才會變成 pointer。故 (*link)->data
才能取到 data。須注意 *
與 ->
的 prioirty,因為 ->
priority 比較高,因此要加括號。(*link)->data < newt->data
BB
(*link)->data < newt->data
時, *link
要移動到下一項,但因為 c 只有 call by value
,因此要改變指標內的值需要傳入位置。link = &(*link)->next
insert_v1
為第一個 insert。稱之為 "ori insert"insert_v2
為第二個 insert,也就是 pointer to pointer。稱之為 "tasted insert"clear
為清除 linked listinsert_v1
insert_v2 (tasted insert)