contributed by< JimmyLiu0530
>
進階電腦系統理論與實作
題目給定 linked list 結構定義為:
且已知不存在 circular (環狀結構) 情況下,對單向 linked list 進行操作
圖例:
add_entry
新增節點,當 linked list 沒有內容時,必須由開發者更新指向開頭的指標。因此實際得到 reference,而非 copy
程式碼如下:
運作原理如下:
assert(new_node)
,用來檢查new_node是否合法Note
->
的執行順位大於 &
,所以要先進行 ->
運算再運算 &
remove_entry
移除指定節點,指向開頭的指標可能因此變更,所以需要用到 a pointer to a pointer (指標的指標)
程式碼如下:
運作原理如下:
swap_pair
交換一對相鄰的節點,取自 LeetCode: Swap Nodes in Pairs,給定
1->2->3->4
,則該回傳2->1->4->3
程式碼如下:
運作原理如下:
node = &(*node)->next->next
,因為此 function 為兩兩交換,因此下一輪 node pointer 應指向目前這對的尾,如下所示:*node = (*node)->next
,使 head 改指向該對的尾(e.g. node2),如下所示:reverse
將給定的 linked list 其內節點予以反向,即
1->2->3->4
,則該回傳4->3->2->1
程式碼如下:
運作原理如下:
head->next = cursor; cursor = head
,如圖先將 head->next (i.e. node1) 指向 cursor 指的 NULL,再將 cursor 指向 headswap_pair_revised
& reverse_revised
說明: 利用指標的指標對 swap_pair
及 reverse
兩函式做改寫,來達到不需回傳整串 linked list 的 head
swap_pair_revised
程式碼如下:
主程式呼叫:
swap_pair_revised(&head);
運作原理如下:
swap_pair
只有傳入 parameter 的方式不同,差別在於 swap_pair
採 pass by value 的方法;而 swap_pair_revised
則是採 pass by reference 的方法。有關 pass by value 跟 reference 的詳細解說,可到 Pass by value vs Pass by reference 觀看reverse_revised
程式碼如下:
主程式呼叫:
reverse_revised(&head);
運作原理如下:
head
改成 *indirect
)也須做修改reverse
函式首先,建立遞迴演算法有幾個重點: (a) 終止條件 (b) 將原問題變成與其相似且規模較小的問題
程式碼如下:
主程式呼叫:
head = rev_recursive(head);
運作原理如下:
什麼是 Fisher–Yates shuffle
?
用來將一個有限集合生成一個隨機排列的方法,簡單來說,該算法可以洗牌序列。該算法產生無偏頗的排列,代表每種排列的可能性均等。
程式碼如下
主程式呼叫:
Fisher_Yates_shuffle(&head);
運作原理如下:
先說明 swap
函式,主要將第 p 跟第 q 個節點交換
第11-24行 先找到第 p 跟第 q 個節點的位置,並記錄在 currP 及 currQ, prevP 跟 prevQ 則分別記錄 currP 及 currQ 的前一個節點
第26-27行 需考慮 p==1 的情況,也就是第 p 個節點是 head
第33行 之所以這裡不用 if-else 是因為在給定的前提中,1 <= p <= q。當 q=1 時,
p 勢必也是 1 ,因此會在 line 8
retrun 掉了
第36-38行 做一些 next
pointer 的交換
此 swap
函式因為是 linked list,所以不像 array 在給定第 p 跟第 q 個元素做交換下可在O(1)完成,需 。
接著看 Fisher_Yates_shuffle
函式,此函式精神在於在第 p 輪中,會隨機找一個介於 p 跟總節點數的數字 q,並將第 p 跟第 q 個交換
第44-50行 計算 linked list 的總節點數
第55-60行 從 linked list 的第一個節點開始,在之間隨機找一個節點做交換,再來換第二個節點…以此類推,一直重複做到倒數第二個節點
此Fisher_Yates_shuffle
函式的時間複雜度為 ,但空間複雜度只需 。