contributed by <sssssssttttttt >
特別將這個函數list_add
以圖表示過程
當 node_t
要插入 list
原本會長這樣
加入後變這樣
也就是加入在前端。
begin
和end
來儲存任何子串列的頭跟尾的位置(下圖),stack 每次都會將左中右的子串列儲存在 stack 中,其中最上端的串列位置所指的子串列,因為屬於右邊所以平均值會最大,用以日後 pop stack 時會先加入最大的數,可以回去看list_add
的加入方法是從右到左放入數字。\((f > b > c,d,e\) )知道上述的變數用途後,可以把問題分成兩部分L==R
與L!=R
每次進入迭代時都會先取 stack 最上端分別給 L
與R
L==R : 代表這個子串列只剩一個元素可以直接加入result
L!=R : 代表這個子串列還得繼續將它分成左右子串列再繼續處理
綜合以上各個模組討論就可以把整個程式串起來了 !
(*left)->next)
走訪全串列left
串列 \(>pivot\) 之元素加入 right
串列&list_tail(left)
&list_tail(right)
node_t
內包含struct list_head
去做串接struct list_head
地址 struct list_head *begin[2 * number_of_data]
配置大小的必要性這裡我採用不多花空間去紀錄所有值,然後再取中位數,我選擇從左到右比大小,但要比大還比小是交替選擇,來近似取中位數的方法,以下是我尋找 pivot 的程式碼
考慮到極端值會影響執行時間,因此我決定犧牲一點時間去選擇 pivot,雖然感覺多做一些操作,但實際排序結果卻快上很多
引用C語言規格書 6.3.2.3 ,整數與指標間是可以合法轉換
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
static struct pair find_run(...)
中將 run size 轉型成指標後儲存在 head->next->prev
tp
為儲存所有 run 的串列,注意tp->prev...->prev
資料比tp
還早進來表示越舊static struct list_head *merge_collapse(...)
合併判斷標準為最新或者次新的 run 往後數三個來判斷 run size 大小,當最新的兩個\(( A、B )\)大小大於最舊的那個\(( C )\)且如果 \(A>C\) 就將 \(B、C\) 合併,否則 \(A、B\) 合併
NULL
中斷串列連結成單向串列result
這個結構進行包裝,並每次都檢查目前發現的 run 中是否需要進行合併,來保持所有 run size 的平衡stk_size < 3
為止,合併條件當 \(A>C\) 就先合併 \(B、C\) 否則合併 \(A、B\)其中 pprev
為何要宣告為指標的指標? : 根據教材 : 雙向鏈結串列進行節點移去時,會產生的問題。而且 pprev
指向指著自身節點的指標。
變數用途
hlist_head
: 供 hash table 使用hlist_node
: 填入 table 內,內部含有 next 做碰撞的串接static inline void node_add(...)
: 將索引和值設定好在 node
的結構中透過,再利用 inorder size
計算出 hash value 加入在對應的 hash value 的串列
static struct TreeNode *dfs
: 透過find
函數找從 hash table 中找到 inoder node 結構中的索引值,其中因為從 preoder 中找到任意子樹的 root 後就可以從 inoder 中找到左右子數節點的個數,在下列舉個左子樹 dfs 範例 ,pre_low 屬於目前 preoder 中左子數節點索引最低點,所以要繼續走訪的話,最低點索引要再加一,最高點索引就是從 inoder 推算出來的左子樹節點的個數(idx - in_low)
進行相加得到左子數節點在 preoder 中索引的範圍
preorder
inorder
static struct TreeNode *buildTree(...)
:INIT_HLIST_HEAD
)並計算雜湊值到對應的 in_heads
這個 hash table ( by node_add
),最後就透過dfs
去建立整顆樹,即可完成原理
這個 LRU 是使用 hash table 來實作,首先分析它的結構成員的用途
LRUCache
:
capacity
: cache 總容量count
: chche 目前的使用量dhead
: 紀錄整個 hash node 的最近使用順序hhead
: 整個 hash tableLRUNode
:
node
: 用來儲存碰撞的串列元素link
: 紀錄在 dhead
中的位置有了以上的結構成員用途後,就可以知道整個程式碼的流程,特別的一點是每次使用lRUCacheGet
、lRUCachePut
都必須更新 cache 結構中紀錄 hash node 的使用順序,因為不管是最近讀取或者最近放入,都算剛使用過,因此都會有以下這段程式碼,當找到對應的 key 時必須將 dhead 中自身往前挪移
另外如果 cache 容量使用達到限制,必須移除 least recently used 的節點