contributed by < steven523 >
此題參考〈Optimized QuickSort — C Implementation (Non-Recursive)〉,透過 quicksort() 實作非遞迴的快速排序法,並運用 stack 來模擬遞迴函式呼叫
以下是鏈結串列的結構體,有一個 long 儲存的資料及一個 next
指標,可判斷其為單向的鏈結串列,還有兩個指標為 left
和 right
首先程式一開始為 test_arr
這個整數型態的陣列配置記憶體空間,接著指派 0~99999 給它,並呼叫 shuffle
函式將陣列中的元素打亂
list_construct
函式用於建立一個新節點,並將其插入到鏈結串列 list
的頭部,然後返回鏈結串列的首節點
所以下列程式整體上來說是透過 while 將 test_arr[count]
的值逐一插入 list
頭部,最終形成的鏈結串列會與 test_arr[count]
順序相反
list_add
與 list_construct
用途相似,都是將節點插入鏈結串列的頭部,只差在 list_construct
傳入值的型態是 int
,所以要為其先用 malloc
配置一個記憶體位置
qiuck_sort
函式在每一輪迴圈都會經過以下步驟
首先宣告L
及 R
分別指向鍵結串列的第一個節點與最後一個節點,並指派第一個節點為 pivot,p
為下一個節點,最後將 pivot
與原鏈結串列分開
利用以下程式碼走訪整個串列,並判斷目前的節點是否大於 pivot->value
,是的話加入 right
,否則加入 left
此為原鏈結串列初始化過後的樣子,left
和 right
在每次回全結束前都會重設為空的鏈結串列
因為 p
指向的值 2 小於 pivot
的 3,所以將 p
指向的節點透過 list_add
函式加入 left
頭部, 接著 p
指向下一個節點
持續同樣操作直到整個鏈結串列走訪完的結果會像下圖
最後透過上述程式碼將 left
頭尾放入 beg[i], end[i] 中來取代原本的整個佇列的位置,right 頭尾則放入 beg[i+2], end[i+2],並將 i+2 後重新下輪迴圈進行排序
如果 L != R
成立,即 beg[i]
等於 end[i]
,代表此佇列只有一個節點,此時就將該節點加入 result
。接著 i– 後會將上圖 pivot
節點再加入 result
,最後對上圖 left 進行排序直到整個鏈結串列排序完成。
整體插入 result
順序為 right
-> pivot
-> left
,因為 list_add
是從頭部插入所以能知道結果是由小到大排序好的鏈結串列
不用列出參考題解,你專注在程式碼的原理即可。
Tim sort 為 Tim Peter 提出,結合了合併排序和插入排序的特點
首先識別出資料中已排序的子序列 (這些子序列稱為 run),然後透過不斷合併這些 run 來達成全資料範圍的排序
Timsort 採用一組堆疊 (stack) 來暫存 run,此舉是為了避免在一開始就掃描整個資料範圍來產生 run,從而降低記憶體開銷。過程中,Timsort 運用 merge_collapse 函式來確保堆疊上的 run 長度保持平衡。該函式主要檢查堆疊頂端的 3 個 run 是否滿足以下原則:
不用列出參考題解,你專注在程式碼的原理即可。
透過 preoreder 和 inorder 的二元樹排序,重建原本的二元樹。
參考 Linux 核心的 hash table 實作
hlist_node 間接指標
next
指向相鄰的節點本身,而 pprev
指向指著自身節點的指標*pprev
是指上個節點的 next
指標**pprev
就是上一個節點本身,所以通過執行 *pprev = next;
就代表將 n 的上一個節點的 next
指向 n 的下一個節點,實現將 n 從鏈結串列中移除的操作hlist_add_head
這個函式執行 hash table 中,將 n
插入雙向鏈結串列。將 hlist_node n
插入於 hlist_head h
的前端。
find
將傳入的 num
尋找雜湊表中的位置索引。宣告 hash
得知該節點放於雜湊表中的哪個槽,並以 hlist_for_each
走訪每個節點,尋找節點並回傳索引。
dfs
Preorder 中第一筆資料為根,而 Inorder 中左子樹及右子樹之資料分別在根的左右,所以利用 find()
得到根的 index 後,即可切割出左子樹及右子樹,且因為 Preorder 中左子樹之資料必定在右子樹之資料前面,所以先對左子樹遞迴做 dfs()``,接著對右子樹遞迴做
dfs()` 便可得到整棵樹
node_add
這裡執行的是建立一個 node 並將其存放至 hash table。建立一個新節點,宣告 hash
決定該節點要存放於 hash table 的哪個槽裡,最後使用 hlist_add_head
將該節點加入 hash table
buildTree
透過前序和中序來完成