主要移植了內(nèi)核中的 list,rbtree。使得這2個(gè)數(shù)據(jù)結(jié)構(gòu)在用戶(hù)態(tài)程序中也能使用。
同時(shí)用 cpputest 對(duì)移植后的代碼進(jìn)行了測(cè)試。(測(cè)試代碼其實(shí)也是使用這2個(gè)數(shù)據(jù)結(jié)構(gòu)的方法)
內(nèi)核代碼的如下文件:(內(nèi)核版本 v3.2 debian 7.5源碼)
對(duì)上面的代碼進(jìn)行了一些簡(jiǎn)化,只留了常用的函數(shù)。同時(shí)刪除了其中和內(nèi)核相關(guān)的部分。
主要內(nèi)容:
Linux中的鏈表用法與一般數(shù)據(jù)結(jié)構(gòu)書(shū)中介紹的用法有些不一樣。
Linux內(nèi)核中,為了保證鏈表的通用性,將鏈表的節(jié)點(diǎn)結(jié)構(gòu)單獨(dú)抽取了出來(lái),也就是將鏈表的結(jié)構(gòu)和鏈表的數(shù)據(jù)分開(kāi)定義。
一般數(shù)據(jù)結(jié)構(gòu)的書(shū)中介紹到的鏈表都是將鏈表的數(shù)據(jù)和鏈表的結(jié)構(gòu)一起定義的。
注:具體介紹可以我之前的博客參見(jiàn):http://www.CUOXin.com/wang_yb/archive/2013/04/16/3023892.html 中的 1.2節(jié)
里面很重要的一點(diǎn)就是:鏈表結(jié)構(gòu)和數(shù)據(jù)分開(kāi)后,是如何通過(guò)鏈表節(jié)點(diǎn)結(jié)構(gòu)來(lái)獲取數(shù)據(jù)的?
帶有safe的函數(shù)或者宏都是可以用于多線程的
1.2 修改部分No. | 主要 函數(shù) | 說(shuō)明 |
1. | list_add | 在 head 之后追加一個(gè)節(jié)點(diǎn) |
2. | list_add_tail | 在 head 之前追加一個(gè)節(jié)點(diǎn), 也就是在末尾追加一個(gè)節(jié)點(diǎn) |
3. | list_del | 刪除一個(gè)節(jié)點(diǎn), 并將這個(gè)節(jié)點(diǎn)的next, prev 置為 NULL |
4. | list_del_init | 刪除一個(gè)節(jié)點(diǎn)并初始化刪除的節(jié)點(diǎn) |
5. | list_replace | 替換一個(gè)節(jié)點(diǎn) |
6. | list_replace_init | 替換一個(gè)節(jié)點(diǎn), 并初始化被替換的節(jié)點(diǎn) |
7. | list_move | 移動(dòng)節(jié)點(diǎn)到 head 之后 |
8. | list_move_tail | 移動(dòng)節(jié)點(diǎn)到 head 之前 |
9. | list_is_last | 判斷節(jié)點(diǎn)是否是鏈表中最后一個(gè) |
10. | list_empty | 判斷鏈表是否為空 (即, 是否只有 head 節(jié)點(diǎn)) |
11. | list_is_singular | 判斷鏈表中是否只有一個(gè)節(jié)點(diǎn) (除了 head 之外) |
12. | list_cut_position | 將1個(gè)鏈表截?cái)酁?個(gè)鏈表 |
13. | list_splice | 將2個(gè)鏈表合并為1個(gè)鏈表, @list中的所有節(jié)點(diǎn)(不包括list)加入到 head 之后 |
14. | list_splice_tail | 將2個(gè)鏈表合并為1個(gè)鏈表, @list中的所有節(jié)點(diǎn)(不包括list)加入到 head 之前 |
15. | list_splice_init | 同 list_splice, 最后會(huì)初始化 @list |
16. | list_splice_tail_init | 同 list_splice_tail, 最后會(huì)初始化 @list |
No. | 主要 宏 | 說(shuō)明 |
1. | list_entry | 獲取包含此節(jié)點(diǎn)的 struct |
2. | list_first_entry | 獲取包含此節(jié)點(diǎn)的 首個(gè) struct |
3. | list_for_each | 從 head節(jié)點(diǎn)之后一個(gè)節(jié)點(diǎn)開(kāi)始向后循環(huán) |
4. | list_for_each_prev | 從 head節(jié)點(diǎn)之前一個(gè)節(jié)點(diǎn)開(kāi)始向前循環(huán) |
5. | list_for_each_safe | list_for_each 的安全版本, 即, 循環(huán)時(shí)即使有其它線程刪除節(jié)點(diǎn)也可正常運(yùn)行 |
6. | list_for_each_prev_safe | list_for_each_prev 的安全版本 |
7. | list_for_each_entry | 同 list_for_each, 只是參數(shù)不同 |
8. | list_for_each_entry_reverse | 同 list_for_each_prev, 只是參數(shù)不同 |
9. | list_for_each_entry_continue | 同 list_for_each_entry, 但不是從頭(head)開(kāi)始循環(huán)的 |
10. | list_for_each_entry_continue_reverse | 同 list_for_each_entry_reverse, 但不是從頭(head)開(kāi)始循環(huán)的 |
11. | list_for_each_entry_from | 從指定位置開(kāi)始向后循環(huán) |
12. | list_for_each_entry_safe | list_for_each_entry 的安全版本 |
13. | list_for_each_entry_safe_continue | list_for_each_entry_continue 的安全版本 |
14. | list_for_each_entry_safe_from | list_for_each_entry_from 的安全版本 |
15. | list_for_each_entry_safe_reverse | list_for_each_entry_reverse 的安全版本 |
構(gòu)造如下場(chǎng)景,用來(lái)測(cè)試上述列出的所有的 list 操作:
1. 構(gòu)造用來(lái)測(cè)試的 struct:(為了使得測(cè)試結(jié)果一目了然,struct盡量簡(jiǎn)單)
struct test_struct {int num; struct list_head head;};
2. 逐個(gè)函數(shù)進(jìn)行測(cè)試,使用測(cè)試框架 cppUTest
3. 宏 相關(guān)的暫時(shí)沒(méi)有測(cè)試
4. 運(yùn)行測(cè)試非常簡(jiǎn)單(前提是得安裝 cpputest)
make./test_list -v2. rbtree 介紹1.1 簡(jiǎn)介
紅黑樹(shù)是一種自平衡的二叉搜索樹(shù)。紅黑樹(shù)是有序的。
注: 具體介紹可以我之前的博客參見(jiàn):http://www.CUOXin.com/wang_yb/archive/2013/04/16/3023892.html 中的 第4節(jié)
這里只補(bǔ)充一點(diǎn),紅黑樹(shù)雖然有些復(fù)雜,但是它的查找,插入,刪除操作的效率還不錯(cuò)。查找,插入,刪除的時(shí)間復(fù)雜度都是O(log n) n是樹(shù)中元素?cái)?shù)目
1.2 修改部分為了是 rbtree 更加簡(jiǎn)單,暫時(shí)刪除了以下內(nèi)容:
注意: rbtree 的對(duì)外接口中沒(méi)有插入node的接口,只有在插入node之后改變node顏色的接口
可能是由于node的順序因具體struct而異,所以沒(méi)法統(tǒng)一實(shí)現(xiàn)
No. | 主要 函數(shù) | 說(shuō)明 |
1. | rb_set_parent | 設(shè)置父節(jié)點(diǎn)的地址 |
2. | rb_set_color | 設(shè)置節(jié)點(diǎn)顏色 |
3. | rb_init_node | 初始化節(jié)點(diǎn) |
4. | rb_insert_color | 設(shè)置新插入節(jié)點(diǎn)的顏色 |
5. | rb_erase | 刪除一個(gè)節(jié)點(diǎn) |
6. | rb_next | 返回當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) |
7. | rb_prev | 返回當(dāng)前節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn) |
8. | rb_first | 返回第一個(gè)葉子節(jié)點(diǎn)(也就是最左邊的葉子節(jié)點(diǎn)) |
9. | rb_last | 返回最后一個(gè)葉子節(jié)點(diǎn)(也就是最右邊的葉子節(jié)點(diǎn)) |
10. | rb_replace_node | 替換rbtree中的一個(gè)node(只是簡(jiǎn)單的替換,沒(méi)有管替換的顏色對(duì)不對(duì),數(shù)據(jù)的順序?qū)Σ粚?duì)) |
No. | 主要 宏 | 說(shuō)明 |
1. | rb_parent | 獲取父節(jié)點(diǎn)的地址 |
2. | rb_color | 節(jié)點(diǎn)的顏色 |
3. | rb_is_red | 是否紅節(jié)點(diǎn) |
4. | rb_is_black | 是否黑節(jié)點(diǎn) |
5. | rb_set_red | 設(shè)置節(jié)點(diǎn)為紅色 |
6. | rb_set_black | 設(shè)置節(jié)點(diǎn)為黑色 |
7. | RB_ROOT | 初始化根節(jié)點(diǎn) |
8. | rb_entry | 獲取包含rbtree node的struct |
9. | RB_EMPTY_ROOT | 判斷是否只有根節(jié)點(diǎn) |
10. | RB_EMPTY_NODE | 判斷節(jié)點(diǎn)是否剛初始化,還沒(méi)有加到樹(shù)中 |
11. | RB_CLEAR_NODE | 設(shè)置節(jié)點(diǎn)的父節(jié)點(diǎn)也指向自己 |
rbtree.c 中函數(shù)都比較簡(jiǎn)單,比較復(fù)雜的是 rb_insert_color 和 rb_erase
這2個(gè)函數(shù)還涉及其它未公開(kāi)的函數(shù) __rb_rotate_left, __rb_rotate_right, __rb_erase_color
1. __rb_rotate_left : 左旋,即,以參數(shù) node 為中心點(diǎn),逆時(shí)針旋轉(zhuǎn)。左旋可以調(diào)整右子樹(shù)的高度
下面的4副圖演示了左旋時(shí),struct rb_node 的 left 和 right 指針的變化。
下圖是最復(fù)雜的一種情況,即所有相關(guān)節(jié)點(diǎn)的左右子樹(shù)不為空的情況
2. __rb_rotate_right : 右旋,即,以參數(shù) node 為中心點(diǎn),順時(shí)針旋轉(zhuǎn)。右旋可以調(diào)整左子樹(shù)的高度
下面的4副圖演示了右旋時(shí),struct rb_node 的 left 和 right 指針的變化。
下圖是最復(fù)雜的一種情況,即所有相關(guān)節(jié)點(diǎn)的左右子樹(shù)不為空的情況
3. rb_erase : 刪除節(jié)點(diǎn),調(diào)用 __rb_erase_color 調(diào)整顏色
下圖演示刪除節(jié)點(diǎn)時(shí),struct rb_node 的 left 和 right 指針的變化。
下圖是最復(fù)雜的一種情況,即所有相關(guān)節(jié)點(diǎn)的左右子樹(shù)不為空的情況
4. __rb_erase_color : 刪除節(jié)點(diǎn)后,調(diào)整被刪除節(jié)點(diǎn)后節(jié)點(diǎn)的顏色
被刪除節(jié)點(diǎn) A 的位置由被刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) B(即被刪除節(jié)點(diǎn)的右子樹(shù)中最左的節(jié)點(diǎn))替換。
調(diào)整的顏色就是 B 節(jié)點(diǎn)的 child 和 parent
刪除時(shí)各種情況的分析參見(jiàn):http://zh.wikipedia.org/wiki/紅黑樹(shù)
5. rb_insert_color : 設(shè)置新插入節(jié)點(diǎn)的顏色,調(diào)整rbtree的平衡
插入的位置需要自己定義,這個(gè)函數(shù)只是調(diào)整插入后節(jié)點(diǎn)的顏色
插入時(shí)各種情況的分析參見(jiàn):http://zh.wikipedia.org/wiki/紅黑樹(shù)
1.5 使用示例構(gòu)造如下場(chǎng)景,用來(lái)測(cè)試上述列出的所有的 rbtree 操作:
1. 構(gòu)造用來(lái)測(cè)試的 struct:(為了使得測(cè)試結(jié)果一目了然,struct盡量簡(jiǎn)單)
struct test_struct { int num; struct rb_node node;};
2. 逐個(gè)函數(shù)進(jìn)行測(cè)試,使用測(cè)試框架 cppUTest
3. 宏 相關(guān)的暫時(shí)沒(méi)有測(cè)試
4. 運(yùn)行測(cè)試非常簡(jiǎn)單(前提是得安裝 cpputest)
make./test_rbtree -v
相關(guān)測(cè)試代碼下載
新聞熱點(diǎn)
疑難解答
圖片精選