contributed by < ZhuMon
>
linux2020
2020q1
的意思是 2020 年的第 1 季,顯然我們的開學日就在這範圍
原來如此,之後會注意
1
本文皆以 addr(a) 代表 a 的位址, link(a) 代表 a->addr
HackMD 內文的縮排 (indention) 深度不要太深,不然難以編輯和檢測語法問題
好的,會再思考一下架構
insert_node
從 function 名稱可以猜出這個 function 可能是要在 linked list 插入一個 node
這個 function 傳入的參數有兩個,一個是 list **l
,一個是 int d
*l
指向的 node 有三種可能
- 粗略地往下掃過,在
insert_node()
中,沒有看到將*l
移動很多步的程式碼( e.g.while
、for
),所以可以判定新的 node 會在*l
的旁邊- 由於 XOR linked list 為變相的 doubly linked list,所以第 1 項與第 3 項是相同的
d
可以從第 13 行 tmp->data = d
得知是新 node 的 data
接下來思考 if-else 的功用
*l
為 NULL
,也就是傳入的 linked list 為空,於是將新增的 node: tmp
的 addr
設為 NULL
addr
指定為前後兩個 node address 的 XOR以數學描述如下
= addr(b)
case 1 : *l
指向 a
(linked list 的第一個 node)
*l
最後會指向 tmp
initial
= addr(b)
line 18
line 19
*l = tmp;
符合設想
case 2 : *l
指向 b (linked list 的中間 node)
插入新的 node 到 linked list 的中間(b 的前面或後面)
or
*l
指向 b
或 tmp
initial
line 18
line 19
與設想不同
case 3
結論
insert_node
會在 linked list 插入一個 node,視傳入的 *l
位置為何*l
為第一個,則在前面插入;若是最後一個,則在最後插入*l
指向新 nodedelete_list
l
存在,才進入 while
while
前的狀態
以 addr(a) 代表 a 的位址, link(a) 代表 a->addr
while
後,會由一個指標 next
存放
若l
指向a
next
存在,進入 line 28
可以發現 if
裡,會將 next
指向的 node 的 link 設為下一個 node 的 address
line 29 將 l
指向的 node 釋放
l
指向 next
指向的 node從前面兩個 function 可以歸納出 XOR Linked List 的幾個特性
一開始 if
內判斷傳入的 start
是否存在,以及是否超過一個以上的元素
可參照
insert_node()
若start->addr
為NULL
,則代表 list 內只有一個元素
從變數名稱可以看出接下來可能是要把 Linked list 拆成兩個
用看的可能一時無法知道接下來程式碼的用途,所以試著用數學運算
以下為已知
line 39 設定 pointer
因為第一個以及最後一個 node 所存放的 link 都是其旁邊的 node address,所以 right
可以輕易地藉由 start->addr
得到第二個 node address
line 40~41 斷開 Linked list
接下來分別將 left
、right
丟進 sort
,遞迴呼叫,因為左邊都只有一個,所以每次的分開應該會長這樣
進入重頭戲: for
line 48~50 和 line 62~64 可以一起看,又因為 left
經過遞迴呼叫後,都只會剩下一個 node,所以 line 49 的 if
根本不會進入,是以 right
來解說
這三行將 next
指向 right
隔壁的 node,若直接取用 right->addr
當作下一個 node 的 address ,right
必定為最前面的 node 或是 link 存放下一個 node 的 address,所以
終於要來解題了,line 52~60 和 line66~74 是對稱的,所以也可以一起看。
這裡第一個 if
限制 merge
為 NULL
時才能進入,掃過整個 for
,並沒有看到將 merge
重設為 NULL
,也就是說只有第一次進入才有可能進入第一個 if
只有將
merge
設為left
,left
為NULL
又不可能進入 line 48
假設第一次進入 for
是進入 line 66 的 else
。
進入 line 67,將 start
和 merge
都設為 right
所指向的 node,並且斷掉與其他 node 的連結,然後 right
指向 next
for
是 a->data < c->data
,也就是說會進入 line 48,將 Linked list 分開後,應該要合起來,所以應該要想辦法將 left
接到 merge
或 start
後面
merge->addr
,也就是說 LL1
要存放上一個(NULL
)的位址以及下一個(left
)的位址的 XORNULL
merge
的 link,因為正常的 XOR Linked list 最後一個 node 的 link 一定是上一個 node 的 addressLL1 = XOR(merge->addr, left)
left->addr
,可以從上圖看到此時 left->addr
為 NULL
,由於 left
即將成為最後一個 node,所以必定存放上一個 node 的 address,也就是 merge
LL2 = merge
merge
向前移動LL3
和 LL4
可以此類推LL3 = XOR(merge->addr, right)
LL4 = merge
最後將 start
回傳,合併 Linked List,合併的概念如下
也就是一個 Insertion Sort
2
TODO:
- 第一題延伸問題
- 第二題