contributed by < willwillhi1
>
先補一些相關的知識
treesort 基本的做法是對所有要排序的元素建立二元搜尋數,然後就可以從中列出排序數組。經典的使用時機就是用在 online
的情境之中也就是會對這個數組有較多的操作(插入、刪除等)。
所以如果是用在 one-time sort
,還是用 quick sort
或 merge sort
就可以了。
red-black tree 規則:
root
節點一定是黑色。leaf(nil)
都是黑色。node
是紅的,則它的 children
都是黑的。leaf
,途中經過的黑色節點數量都會相同,也就是說從 root
到某個 leaf
的 simple path
一定不會超過從 root
到任何一條其他這樣的 path
的兩倍長。插入、搜尋、刪除的時間複雜度最差都是
基本旋轉操作可以分成: Left Rotation
、Right Rotation
插入的點預設都是紅色。
插入的 case
:
uncle
是紅的,重新標記顏色後往上層做檢查uncle
是黑的或者是 nil
,可以分成以下情況:
LL
: 做一次 Right Rotation
即可。LR
: 先做一次 left Rotation
,就會變成 LL
,然後再做一次 Right Rotation
。RR
: 做一次 Left Rotation
即可。RL
: 先做一次 right Rotation
,就會變成 RR
,然後再做一次 left Rotation
。grandparent
和新的 uncle
的顏色互換即可。研讀 treesort.c
首先看到結構體 node_t
,記錄了該節點的顏色 color
、在紅黑樹中的左右節點 left, right
以及在原本陣列中的下一個節點 next
和其值 value
。
cmap_internal
記錄整個 map
的資訊,有 key
, element
, map
的 size
, 也記錄了 end
, most
, least
和比較的函式 comparator
。
定義紅色是 0
,黑色是 1
這裡使用的技巧是利用 node_t
的位址一定會對齊 long
,再加上系統是 64
位元,所以 long
是 8 byte
,換句話說 node_t
的位址的末 3
位一定都是 0
,所以這邊就利用這三個 bits
來表示顏色。
最後要找該 node
的 parent
就把 color
末三碼歸零,反之要找 color
就是直接用最低的一位判斷即可。
同理也可以判斷出
這邊第七行的註解說是標成 black
,所以應該是 rb_set_red
cmap_l_l
, cmap_l_r
, cmap_r_r
, cmap_r_l
代表在平衡紅黑樹時會處理的四種情況,並會在 cmap_fix_colors
裡呼叫。
cmap_insert
裡的 for
迴圈部分是在紅黑樹裡尋找可以插入的位置,比較出來的結果 res
如果小於零代表往左走,反之則往右走,最後的中止條件就是如果走訪到的節點為空,就直接做插入的動作然後跳出迴圈。
最後看到 tree_sort
,輸入是一個需要排序的陣列,所以一開始要做的是建立一個 map
並逐一地把節點輸入進去,這邊有用到 indirect pointer
的概念,所以在移動到下一個節點時要用 list = &(*list)->next
。
全部的節點都輸入到紅黑樹後還要把原本的陣列重新依照順序串接起來也就是 for
迴圈的部分,最後把尾端的點的 next
指向 NULL
。
延伸問題,將 treesort
整合進 lab0-c
另外開一個筆記: treesort
計算 ,且 x > 0
這裡的程式原理是在算從最高位 1
到最低位總共幾位,但是這樣會造成 2
和 3
有同樣的結果 2
,不符合取上界的需求,所以如果輸入是 2
的冪就可以通過 x--
來避免這個情況,最後 2
會回傳 1
,3
會回傳 2
。