contributed by < JeffBla >
AAAA = &l->head
BBBB = before
CCCC = &(*p)->next
DDDD = item->next
此函式是將節點 item
插入到 before
之前,在插入之前,需要知道指向 before
的節點,以修改節點順序,因此 for 的流程:
next
或 head
指向 before
則代表所操控的指標為 before
的前一個節點的 next
,即我們希望插入的位置,當到達此情況,則停止迴圈。最後,因為找到目標指標所以將此指標指向欲新增的節點,並維護後續節點。其函式流程圖如下:
假設一開始的鏈結串列如下
初始化,將 pointer to pointer 指向 &list->head
,利用 pointer to pointer 控制指標以去除特例。
當找到目標,則另用 pointer to pointer 控制 next
或 head
指標,插入新節點。
最後將新節點指向 before
完整插入。
主要測試函式為 test_list
,主要測試三個項目
每項目由
N
項N
想法:使用 list_insert_before 進行將鏈結串列 2 依據遞增插入到 鏈結串列 1 的合併演算法。
EEEE = (*pred_ptr)->r
FFFF = &(*pred_ptr)->r
find_free_tree
從 root
找到 target
並回傳指向 target
的指標的指標,也就是指標的指標指向 l
或 r
。find_predecessor_free_tree
找到能夠替換的 target
的節點。此函式刪除二元搜尋樹中的特定節點。首先找到指向 target
的指標的指標。判斷欲刪除節點之子嗣的存在與否,如果沒有則直接刪除,若存在其一且唯一,則將後代上提,替換目標節點。若左右兩邊都存在節點且將替換的節點為 target
的兒子,則直接替換,因為其替換的演算法為找尋左子樹中最大值,如果將替換節點為其後代,則代表欲替換節點左子樹不須處理且能夠直接承接 target
之右子樹。若左右兩邊都存在節點但將替換節點不為 target
的兒子,則紀錄 target
左右子樹,遞迴修剪欲替換的節點,待欲替換的節點整理完成,執行替換。
第一種:欲刪除節點沒有子嗣
第二種:存在左或右子代其一
第三種:存在左與右子代
紀錄欲移除節點的左右子樹,以利後續維護。
pred_ptr
找到將替換節點後,利用遞迴,將欲替換節點當作欲移除節點,確保替換後,二元搜索樹結構仍正確。因為替換節點需要做移除並插入的動作,所以利用遞迴將此種操作傳遞到子代,一直到末端。下面是進入迴圈,處理子代的操作:
當子代處理完成,回到 target
的處理。
測試程式碼移除的三種情況。實作找到指向 target
的指標、初始化並插入建二元搜索樹。
以 N 為 1000 節點測試,建造 complete BST ,並依序刪除
之後測試隨機刪除直到節點全被移除。
GGGG = head->prev=prev
HHHH = list_entry(pivot,node_t,list)->value
IIII = list_entry(n,node_t,list)->value
JJJJ = pivot
KKKK = right
此程式碼和運用 Optimized QuickSort — C Implementation (Non-Recursive) 實作非遞迴 (non-recursive; iterative) 的快速排序法程式碼原理相同。
利用 begein
與 end
(在此實作利用 list_tail 取代) 代替分割所需要的遞迴空間及紀錄數值。採用和 list_sort.h 類似風格實作,首先,將環狀改成非環狀並在後續復原 prev
指標,復原環狀與雙向指標的特性。利用 L
代表串列最左, R
代表串列最右進行範圍內的運算,其中 pivot
為最左邊的節點,並將此節點獨立,利用 p
指標遍歷L
到 R
中的節點,將大於 pivot
內數值的節點歸到 right
其他歸到 left
。 最後將 right
、 pivot
、 left
開頭記錄到 begin
,其中 right
所記錄的位置最後面, 其次是 pivot
和 left
,由於 begin
採用堆疊的概念,在排序時,也是 right
完成後才是 pivot
與 left
。 當排序完成, L
與 R
指向相同節點,將此節點記錄到 result
,並使用 begin
執行前面一項鏈結串列排序。
AAAA = list_first_entry
BBBB = list_del
CCCC = list_move_tail
DDDD = list_add
EEEE = list_splice
FFFF = list_splice_tail
利用 ASLR 實作隨機,在 unbiased_random
中乘法可有效地將隨機分佈擴展到目標範圍,透過採用高位而不是使用模數,避免偏差。
list_for_each_entry_safe
是由前到後遍歷, list_move_tail
將每次遍歷的數值加入到特定鏈結串列的末端,形成類似佇列的排列,先插入的節點會在前面,而後插入的在後面,確保了 stable 的性質。若換成 list_move
將每次遍歷的數值加入到特定鏈結串列的前端,則形成如堆疊的排列,先插入的節點在後面,後插入的在前面。
GGGG = 14
HHHH = 2
IIII = 0
JJJJ = 3
KKKK = 2
LLLL = 1
MMMM = ~1
NNNN =
PPPP =