contributed by < ItisCaleb
>
1
透過 ABI 的特性,我們可以將父節點的地址儲存在該節點的 color
欄位中,同時使用 color
欄位的 LSB 來表示該節點的顏色。
接著,我們可以使用位元運算對 color
進行操作,以得到父節點的地址或是節點的顏色。
在 cmap_insert
中,需要先從根節點開始走訪節點,直到找到樹的底端或是 NULL,才能進行插入操作。
在走訪的過程中,res
是比較新元素和當前節點的值的結果,以確定是要往左邊走還是右邊走。如果最終找到了 NULL ,那麼就可以把新元素插入到這個位置上。
在 tree_sort
中,我們把 list
中的節點一個一個放進 map
裡,然後再透過cmap_next
一個一個拿出來,這樣就會是排序好的狀態
最後我們使用把 list
的結尾變成 NULL 並且指向第一個節點
而在觀察程式碼的時候,也看到了一些可以改進的地方
cmap_rotate_left/right
的大部份程式碼幾乎一樣,所以把同樣的部份抽離出來到 cmap_do_rotate
,原本的函式只留下調整要 rotate 的 node
同樣注意到 cmap_l_l
跟 cmap_r_r
交換顏色的程式碼相同,於是也抽離出來到 cmap_swap_color
2
priority queue 分別有 insert 跟 pop 的操作,並且各自有 balanced 跟 unbalanced 的版本
avl_prio_queue_insert_unbalanced/balanced
我們首先將 cur_nodep
指向 root
並且 isminimal
為確認要插入的 node 是否為最小的 flag
接著便用迭代的方式走訪樹,比現在的 node 小就往左走,否則就往右走
如果往右走就表示要插入的 node 不為最小的 node
如果是最小的 node,便更新 queue->min_node
最後我們便將要插入的 node 放到樹上
如果操作是 unbalanced,使用 avl_link_node
,直接把 node 接上
而 balanced 則使用 avl_insert
,在接上 node 之後,函式會去計算並旋轉樹來確保平衡
avl_prio_queue_pop_unbalanced/balanced
pop 會回傳最小的 node
並且把 queue->min_node
更新成下一個 node
最後一樣
unbalanced 會使用 avl_erase_node
balanced 會使用 avl_erase
來確保樹是平衡的
3
LFSR利用一組 binary pattern 作為初始狀態,然後將這組 binary pattern 通過一系列的位元移位、XOR運算等操作,產生出一系列的新數列,這些新數列看起來就像是隨機產生的序列。而LFSR通過改變移位寄存器的位元個數、XOR運算的默認值可以控制生成的數列長度和隨機性質。
LFSR就是一種通過移位、XOR等操作,生成隨機序列的技術。
題目給的 LFSR 實作是一種 Fibonacci LFSR
在這個例子裡 bit 是從左數到右並且從 1 開始
我們把 LSB (64th bit) 及選定的幾個 bit 稱為 tap
總共有幾個步驟
要注意的是選定的 tap 要符合兩項條件
而要產生新的數組就是把輸出的 binary pattern 作為 LFSR 的輸入
在 Linux 的 crypto/jitterentropy.c
中的 jent_lfsr_time
可以看到 Fibonacci LFSR 的實作
題目本身會分配數個 bucket ,並且透過 LSFR 來生成數組把這些 bucket 填滿
N_BUCKETS
是 bucket 的數
N_BITS
則是 N_BUCKETS
以 2 為底的 log
首先我們來看 log2_64
題目定義了一個 log_table_256
,展開來就會是 0 ~ 255 以 2 為底的 log
而 log2_64
可以簡化成下列這樣
方法是先將整數向右位移 32 位,如果移動後的值不為零,就代表最高的 32 個 bit 中至少有一個 bit 是 1,此時可以將整數再向右位移 16 位,以此類推,每次將位移的距離除以 2。當位移的距離為 8 時,就可以找到最左邊有東西的 8 個 bit 及它們的位置。
接著,透過對照 log_table_256
,就能找出這 8 個 bit 對應的 log 值
最後便將位置加上透過 log_table_256
找到的值
bucket_number
是用來把 LSFR 生成的數字限制在 N_BUCKETS
裡
mask111
是從 0~n 都為 1 的 bit pattern
mask011
則是從 0~n-1 都為 1 的 bit pattern
用 mask111
跟 x
去做 and 便可以得到x
0~n 的 bit pattern
如果這個數小於 N_BUCKETS
則回傳
而如果等於的話則將 x
向右位移 n+1 來獲取新的數組並且跟 mask011
and 後回傳
而最後的 fill_buckets
便是透過 LSFR 生成數組並且使用bucket_number
後將輸出放進 bucket裡面
4
這個函式的方法跟測驗 3 的很像,同樣是不斷去找最左邊有東西的 bits
不同的點在於 r
是用 bit operation 去得到 MSB 的位置
而當輸入為 0 的時候會輸出 32
要改進並且讓函式一樣是 branchless 可以套用上一題 bucket_number
最後一行使用的方法