linux内核中的数据结构
http://vinllen.com/linuxnei-he-zhong-de-shu-ju-jie-gou/
https://zhuanlan.zhihu.com/p/58087261
https://blog.csdn.net/wenqian1991/article/details/44515713
https://blog.csdn.net/ace_an/article/details/53813242
?
?
Linux中最重要最常用如下四種:
LIST:鏈表 <linux/list.h>
Linux內核的標準鏈表就是采用“環形、雙向”鏈表形式實現
沿著鏈表移動智能是線性移動
需要隨機訪問的數據,一般不使用鏈表
鏈表存放數據的理想情況是:需要遍歷所有數據、或者需要動態加入/刪除數據
有時首元素會用一個特殊的指針表示,稱為“頭指針”,可以方便的找到鏈表的“起始端”
Linux內核實現特殊性:不是將數據結構塞入鏈表,而是將鏈表結點塞入數據結構
Linux內核鏈表操作函數的復雜度都是O(1),而不管鏈表中元素數目的多少
list_add\__list_add
list_add_tail\__list_add_tail
list_del\__list_del
list_del_init\__list_del_init
list_move\__list_move
list_move_tail\__list_move_tail
list_empty\__list_empty
list_entry\__list_entry
list_splice\__list_splice
list_splice_init\__list_splice_init
Linux內核遍歷鏈表的復雜度是O(n),n是鏈表元素數目
list_for_each
list_for_each_entry
list_for_each_entry_reverse 反向遍歷鏈表,有二原因:①當反向遍歷性能好時;②當遍歷順序很重要時;
list_for_each_entry_safe 該函數允許在遍歷鏈表循環體中刪除元素,普通遍歷函數不允許這樣做
list_for_each_entry_safe_reverse
鏈表操作函數分為外部函數、內部函數,函數同名,只差雙下劃線__,內部函數用prev、next參數
FIFO:隊列 <linux/kfifo.h>
Linux內核通用隊列實現稱為kfifo,實現在文件kernel/kfifo.c中
維護兩個偏移量:
入口偏移(下一次入隊時位置)>=出口偏移(下一次出隊時位置);
入口偏移==出口偏移,說明隊列空了;
入口偏移==隊列長度,說明隊列重置前不能再有入隊操作;
提供兩個主要操作:
入隊enqueue(copy數據到隊列入口偏移位置)
出隊dequeue(從隊列出口偏移copy數據)
隊列操作:
kfifo_alloc 動態創建、初始化 (size需是2的n次冪)
kfifo_init 動態創建、初始化,但使用已分配內存 (size同上)
DECLARE_KFIFO/INIT_KFIFO 靜態聲明,不常用(size同上)
kfifo_in ? 入隊
kfifo_out ? 出隊
kfifo_out_peek ? 不出隊,只返回數據
kfifo_size ? 隊列總體空間(長度)
kfifo_len ? 隊列已用空間
kfifo_avail ? 隊列剩余空間
kfifo_is_empty ? 判定隊列空
kfifo_is_full ? 判定隊列滿
kfifo_reset ? 重置隊列(拋棄所有元素)
kfifo_free ? 釋放kfifo_alloc創建的隊列
映射:
稱為關聯數組,由“鍵<==>值”對兒組成的集合;?
“鍵”是唯一的,“值”關聯到鍵;
映射操作:
Add (key, value) ? 增加
Remove (key) ? 刪除
Value = Lookup (key) ? 查找
Allocate ? 插入鍵值對,產生UID
Linux內核提供了簡單、有效的映射數據結構。但是它并非一個通用的映射;
Linux內核提供它的目標是:映射一個唯一的標識數(UID)到一個指針; (因此并不適合其它場景)
idr數據結構:用于映射用戶空間的UID
idr_init ? 初始化靜態/動態分配的idr
...
二叉樹:
樹,是一個能提供分層的“樹”型數據結構的特定數據結構;
樹,是一個無環、連接的有向圖;
樹,任何一個節點具有0~n個出邊,1個入邊;
節點深度,是從根節點起到達該節點止一共需要經過的父節點數目;
樹的高度,是葉子節點的深度;
二叉樹,任何一個節點最多有2個出邊的樹,即只能有0、1、2個出邊;
BST:二叉搜索樹
規則1:根左分支節點值 < 根節點值
規則2:根右分支節點值 > 根節點值
規則3:所有子樹都是二叉搜索樹
前序遍歷:根節點->左子樹->右子樹
中序遍歷:左子樹->根節點->右子樹
后序遍歷:左子樹->右子樹->根節點
在樹中搜索給定值、按序遍歷都相當快捷;中序遍歷二叉搜索樹時會按照節點值從小到大的順序排序;
自平衡二叉搜索樹
平衡二叉搜索樹:所有葉子節點深度差值都不超過1的二叉搜索樹
自平衡二叉搜索樹:操作都試圖維持平衡(半平衡)的二叉搜索樹
紅黑樹
是一種“自平衡二叉搜索樹”
是Linux主要的平衡二叉搜索樹
具有特殊的著色屬性(或紅色、或黑色)
能維持半平衡結構,其6屬性:
屬性1:所有節點要么著紅色、要么著黑色
屬性2:葉子節點都是黑色
屬性3:葉子節點不包含數據
屬性4:非葉子節點都有2個子節點
屬性5:如果節點是紅色,則它子節點都是黑色
屬性6:一個節點到該節點的葉子節點的所有路徑中,總是包含相同數目的黑色節點;
上述屬性確保:
一個紅色節點不能是其它紅色節點的子節點(或者父節點),即兩個紅色節點不能相連;
從樹的任何一個節點到其葉子節點的路徑都具有相同數目的黑色節點;即最長路徑是紅黑交替路徑,最短路徑是全黑路徑;
所以,最深葉子節點深度,不會大于2倍最淺葉子節點深度; 紅黑樹總是半平衡的;
rbtree: <linux/rbtree.h>
Linux實現的紅黑樹
實現在lib/rbtree.c中
插入效率和樹中節點數目呈現對數關系;(即:時間復雜度與節點數目是對數關系)
根節點由數據結構rb_root描述,創建新紅黑樹,需要分配新的rb_root結構并初始化為RB_ROOT
其它節點由數據結構rb_node描述
未提供搜索和插入操作函數,需要由用戶自己實現(可以使用rbtree提供的輔助函數,但要實現比較操作算子)
其它較少用的:
radixtree:基數樹
數據結構的選擇:
原則一:遍歷操作為主時,優先考慮鏈表;(沒有數據結構能提供比線性算法復雜度更好的算法去遍歷元素)
原則二:排除性能因素,當需要相對較少數據項時,優先考慮鏈表;
原則三:當需要與其它選擇鏈表的代碼交互時,優先考慮鏈表;
原則四:需要大小不明的數據集合,優先選擇鏈表;
原則五:代碼架構復合"生產者/消費者"模式,優先選擇隊列;
原則六:當需要一個定長的緩沖,選擇隊列;
原則七:如果需要映射一個UID到一個對象,選擇映射;
原則八:如果需要存儲大量數據,并且快速檢索,選擇紅黑樹;
轉載于:https://www.cnblogs.com/clemente/p/10887589.html
總結
以上是生活随笔為你收集整理的linux内核中的数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十二周+
- 下一篇: hive in 写法/linux OR