一、核心鍊錶的基本思想
linux核心鍊錶是使用c語言實現的通用鍊錶,為雙向迴圈鍊錶,可以方便的移植使用。它的基本思想是將資料域和指標域分開,核心鍊錶實現的一系列增、刪、改、查操作就是針對指標域的,而資料域則由核心鍊錶的使用者根據實際需求自行完成。這樣一來,核心鍊錶便可以實現通用,而應用程式則可以不用關心鍊錶底層操作的實現,感覺上有點類似c++繼承機制。
二、核心鍊錶原始碼
可從linux核心原始碼中提取,只需要拷貝list.h乙個檔案即可,網上也有不少版本,不過整體的思想是一致的。
三、部分關鍵原始碼
1、指標域結構體型別定義
typedef
struct list_head list_head_t;
鍊錶中所儲存的元素就是這個結構體所包含的內容,只有指標域而沒有資料域,具體如何使用我們下面在具體的例項中探索。
2、煉表頭結點初始化
#define init_list_head(ptr) do while (0)
3、兩個節點之間插入元素
static
inline
void
__list_add
(struct list_head *nw,
struct list_head *prev,
struct list_head *next)
四、例項解析
1、定義頭結點鍊錶以及資料域結構體
struct list_head head;
struct student_t
;
資料域結構體中的指標域元素即為插入鍊錶中的元素
2、初始化頭結點鍊錶並插入元素
int
main
(void
)
node =
(struct student_t*
)malloc
(sizeof
(struct student_t));
if(node)
node =
(struct student_t*
)malloc
(sizeof
(struct student_t));
if(node)
search_student_list
(&head)
;return0;
}
顯而易見,我們只是把資料域中的指標部分插入了鍊錶中,也就是說後面對鍊錶的操作也只能是操作指標域,沒有辦法直接運算元據域。那麼,想要訪問資料域中的資料元素需要怎麼操作呢,我們看一下下面的資料遍歷。
3、鍊錶元素遍歷
void
search_student_list
(struct list_head *list_head)
}
可以看出,遍歷的操作實際也是完全基於指標域元素的,而訪問資料域元素的核心則是根據元素的指標域位址計算出資料域首位址。因為某個元素的指標域位址和資料域位址是連續的(同屬資料域結構體),那麼只需要把指標域位址向前移動一定距離,就可以獲得資料域首位址。
而這個計算的動作由item = list_entry(p,struct student_t,list);來完成。
我們先來看一下它的實現
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
指標域向前移動的距離即使指標域首位址在資料域結構體中的偏移量,如果把資料域結構體的例項放到0位址,那麼指標域首位址既是它在資料域結構體中的偏移量。
這樣,資料域首位址就拿到了。
總結,核心鍊錶儲存、運算元據都是對指標域進行操作,只需要在需要訪問資料域時通過指標域位址計算出資料域首位址即可。
鍊錶的用法
久違的鍊錶 mua mua mua includeusing namespace std struct node 建立1 頭插,逆序 node creat1 int n return head 建立2 尾插 順序 node creat2 int n q next null return head 插...
核心hlist鍊錶
出處 核心中的定義 struct hlist head struct hlist node 這個資料結構與一般的hash list資料結構定義有以下的區別 1 首先,hash的頭節點僅存放乙個指標,也就是first指標,指向的是list的頭結點,沒有tail指標也就是指向list尾節點的指標,這樣的...
linux核心鍊錶
鍊錶是一種常用的資料結構,它通過指標將一系列資料節點連線成一條資料鏈。相對於陣列,鍊錶具有更好的動態性,建立鍊錶時無需預先知道資料總量,可以隨機分配空間,可以高效地在鍊錶中的任意位置實時插入或刪除資料。鍊錶的開銷主要是訪問的順序性和組織鏈的空間損失。一 鍊錶結構 單鏈表結構如下 雙鏈表結構如圖 st...