contributed by < paul90317
>
1
觀察 原始碼
會將顏色與親節點指標的值存在 color
成員裡面,用於存取的程式碼如下
由於指標後兩位(64 bits 系統是三位)都是 0,且我們只會用到其中一位,AAAA
是 (r)->color & ~1
AAAA
不可以是 (r)->color & ~1u
因為在做位元且之前會將 ~1u
從 32 位元擴展到 64 位元,如果是無號擴展再位元且,將會遺失指標高位位元。
從以上程式碼看出紅色是 0,黑色是 1,BBBB
應該是 (r)->color &= ~1
,而 CCCC
應該是 (r)->color |= 1
。
觀察 cmap_insert
函式的程式碼片段
根據該函式的意圖,DDDD
與 EEEE
應是在 cur
不是 internal node 的情況下,存取下一個節點,故 DDDD
是 cur = cur->left
而 EEEE
是 cur = cur->right
。
觀察 tree_sort
程式碼
可以看出 while
迴圈想要將 list
所有節點插入 map
,所以 FFFF
應是 &(*list)->next
以存取下一個要插入的節點。
for
迴圈想要用 cmap_next
走訪節點並構造新的數列,所以 GGGG
應該要是 &(*list)->next
。
順便一提指標的指標讓 list
可以直接在從 map
拿到 node
後再給予值,否則程式碼將變成如下
將於每次判斷 node
是否是第一個節點,或是是以下
將第一個節點分開判斷。
HHHH
是 *list = NULL
對新數列進行收尾。
2
觀察 原始碼
在以上程式碼中,由於 AVL 樹的節點有三個狀態,須給予兩個位元,故 IIII
是 node->parent_balance & ~3
而 JJJJ
是 node->parent_balance & 3
在上述程式碼中,KKKK
應是原本的狀態,故是 avl_balance(node)
,LLLL
是 avl_parent(node)
。
觀察 avl_insert_balance
的程式碼片段
以上程式碼發生於當 node
是 parent
左邊的節點
當樹向左邊傾斜時,應該將 parent
向右旋轉,故 MMMM
是 avl_rotate_right
,
在 node
是向右邊傾斜的情況,NNNN
應該先將node
向左轉再將 parent
向右轉,故是 avl_rotate_leftright
。
3
觀察 原始碼
在查找表 log_table_256
,輸入 0 得到 -1,輸 1 得 0,輸 2、3 得 1,輸 得 ,最高到輸入 255 得 7。
255 所佔用的位元會是輸出值 ,也就是 8 個位元。
以上程式碼我覺得是有點類似遞迴的作法,只是為了更好的效率所以將遞迴函式展開,於是我將該程式傳回遞迴,如下
對照兩者後可以得出
AAAA
是 32 + 16 + 8 是 56BBBB
是 32 + 16 是 48CCCC
是 32 + 8 是 40DDDD
是 32EEEE
是 16 + 8 是24FFFF
是 16GGGG
是 8HHHH
是 0舉一個例子,假設 N_BUCKETS
是 256,N_BITS
就是 8,mask111
是 511,將這個數字對 x 做位元且可能會超出桶數。
當 leq
為 1 時,bucket_number
應輸出正常的桶號,也就是 x & mask111
,故 IIII
是 mask111
。
反之,根據註解,應當要取較少的位元,故 JJJJ
是 mask011
4
因為 ,先將程式碼改寫成方便理解的形式,如下。
經過 21 行的位移後,x 最多只剩 2 個位元,於是 KKKK
就是前一次的結果 r | shift
加上左邊數來第二個位元的結果 x >> 1
故 KKKK
是 r | shift | x >> 1
。
2. 改進程式碼,使其得以處理 x = 0 的狀況,並仍是 branchless
程式碼會在 x--
的時候出問題,最簡單的作法就是使用測驗 3 bucket_number
最後一行的作法,將 ceil_log2
改寫如下