關于雙鏈表實現,一般教科書上定義一個雙向鏈表節點的方法如下:
代碼如下:
struct list_node{
stuct list_node *pre;
stuct list_node *next;
ElemType data;
}
即一個鏈表節點包含:一個指向前向節點的指針、一個指向后續節點的指針,以及數據域共三部分。
但查看linux內核代碼中的list實現時,會發現其與教科書上的方法有很大的差別。
來看看linux是如何實現雙鏈表。
雙鏈表節點定義
代碼如下:
struct list_head {
struct list_head *next, *prev;
};
發現鏈表節點中根本就沒有數據域,這樣的鏈表有什么用?linux內核中定義這樣的鏈表原因何在?
這是因為linux中是通過獨立定義一個鏈表結構,并在結構體中內嵌一個鏈表節點來實現鏈表結構的。這樣有一個好處就是能達到鏈表與結構體分離的目的。如此一來,我們構建好一個鏈表后,其結構示意圖如下:
鏈表的定義及初始化宏定義:
代碼如下:
#define LIST_HEAD_INIT(name){&(name),&(name)}
#define LIST_HEAD(name) /
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { /
(ptr)->next = (ptr); (ptr)->prev = (ptr);/
} while (0)
LIST_HEAD(name)宏用來定義一個鏈表頭,并使他的兩個指針都指向自己。我們可以在程序的變量聲明處,直接調用LIST_HEAD(name)宏,來定義并初始化一個名為name的鏈表。也可以先聲明一個鏈表,然后再使用INIT_LIST_HEAD來初始化這個鏈表。
也即:
代碼如下:
LIST_HEAD(mylist);
與
struct list_head mylist;
INIT_LIST_HEAD(&mylist);
是等價的。
插入操作
代碼如下:
/*僅供內部調用
* Insert a new entry between two known consecutive entries.
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
代碼如下:
//在頭節點后面插入一個節點
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
//在尾節點后插入一個節點
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
刪除操作
代碼如下:
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
新聞熱點
疑難解答