【詳細源自於】
在linux核心中,有大量的資料結構需要用到雙迴圈鍊錶,
例如程序、檔案、模組、頁面等。若採用雙迴圈鍊錶的傳統實現方式,
需要為這些資料結構維護各自的鍊錶,並且為每個鍊錶都要設計插入、刪除等操作函式。
因為用來維持鍊錶的next和prev指標指向對應型別的物件,
因此一種資料結構的鍊錶操作函式不能用於操作其它資料結構的鍊錶。
**********=這樣操作是為了 通用 common**********==
#include #include #include #ifndef _list_head_h
#define _list_head_h
// 雙向鍊錶節點
struct list_head ;
// 初始化節點:設定name節點的前繼節點和後繼節點都是指向name本身。
#define list_head_init(name)
// 等價於 struct list_head foo = ;
// 定義表頭(節點):新建雙向煉表表頭name,並設定name的前繼節點和後繼節點都是指向name本身。
#define list_head(name) \
struct list_head name = list_head_init(name)
// 初始化節點:將list節點的前繼節點和後繼節點都是指向list本身。
static inline void init_list_head(struct list_head *list)
// 新增節點:將new插入到prev和next之間。
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
// 新增new節點:將new新增到head之後,是new稱為head的後繼節點。
static inline void list_add(struct list_head *new, struct list_head *head)
// 新增new節點:將new新增到head之前,即將new新增到雙鏈表的末尾。
static inline void list_add_tail(struct list_head *new, struct list_head *head)
// 從雙鏈表中刪除entry節點。
static inline void __list_del(struct list_head * prev, struct list_head * next)
// 從雙鏈表中刪除entry節點。
static inline void list_del(struct list_head *entry)
// 從雙鏈表中刪除entry節點。
static inline void __list_del_entry(struct list_head *entry)
// 從雙鏈表中刪除entry節點,並將entry節點的前繼節點和後繼節點都指向entry本身。
static inline void list_del_init(struct list_head *entry)
// 用new節點取代old節點
static inline void list_replace(struct list_head *old,
struct list_head *new)
// 雙鏈表是否為空
static inline int list_empty(const struct list_head *head)
// 獲取"member成員"在"結構體type"中的位置偏移
#define offsetof(type, member) ((size_t) &((type *)0)->member)
// 根據"結構體(type)變數"中的"域成員變數(member)的指標(ptr)"來獲取指向整個結構體變數的指標
#define container_of(ptr, type, member) ()
// 遍歷雙向鍊錶
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#endif
struct person
;void main(int argc, char* argv)
// 遍歷鍊錶
printf("==== 1st iterator d-link ====\n");
list_for_each(pos, &person_head.list)
// 刪除節點age為20的節點
printf("==== delete node(age:20) ====\n");
list_for_each_safe(pos, next, &person_head.list)
}// 再次遍歷鍊錶
printf("==== 2nd iterator d-link ====\n");
list_for_each(pos, &person_head.list)
// 釋放資源
list_for_each_safe(pos, next, &person_head.list)
}
輸出:
==== 1st iterator d-link ====
name:1 , age:10
name:2 , age:20
name:3 , age:30
name:4 , age:40
name:5 , age:50
==== delete node(age:20) ====
==== 2nd iterator d-link ====
name:1 , age:10
name:3 , age:30
name:4 , age:40
name:5 , age:50
資料結構 雙向鍊錶的使用
為什麼需要雙向鍊錶?在單鏈表中,有了next指標,這就使得要查詢的下乙個結點的時間複雜度為o 1 可是要查詢是上乙個結點的話,最壞的時間複雜度是o n 了,所以為了克服這一缺點提出雙向鍊錶。雙向鍊錶 雙向鍊錶是在單鏈表的每個結點中,再設定乙個指向其前驅結點的指標域。雙向鍊錶中每個結點都有兩個指標域 ...
資料結構 鍊錶 雙向鍊錶
注意typedef的定義結構,以及dinklist的資料型別 typedef struct dnode dnode,dinklist 注意插入第乙個結點時,prior指標的空指向問題 if l next null 若l後繼結點為空 則省略該步驟 l next prior p 基本 頭插法建立雙向鍊錶...
資料結構 雙向鍊錶
前幾天寫了乙個單向鍊錶,今天參考自己單向鍊錶改寫了乙個雙向非迴圈鍊錶,下面只討論雙向非迴圈鍊錶。雙向非迴圈鍊錶有如下特點 一 雙向鍊錶每個結點都有乙個前驅指標和後驅指標 當然頭結點和尾結點除外 二 雙向鍊錶中的任意乙個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。三 頭結點只有後驅指標沒有前驅...