初学
初学C语言时,对于链表节点的定义一般是这样的:
typedef struct node {
int data;
struct node *next;
} Node;
向链表中添加节点:
void addNode(Node **head, int data) {
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = *head;
*head = newNode;
}
删除节点和遍历节点,就不列举了
进阶
但是到了工作中,对链表的操作一般不这么玩
节点定义
工作中链表节点的定义:
struct dlist {
struct dlist *next;
struct dlist *prev;
};
也就是说是一个双向链表
next
指向下一个节点prev
指向上一个节点- 由于是 双向循环链表,最后一个节点的
next
指向头节点,头节点的prev
指向最后一个节点
然后我们在实际使用时,一般定义一个包含struct dlist结构的自定义结构,例如
struct my_struct {
int data;
struct dlist list;
};
初始化
在使用的时候,一般先初始化
static inline void dlist_init(struct dlist *list)
{
list->next = list;
list->prev = list;
}
//调用这个接口,传入节点的地址即可
struct my_struct test;
dlist_init(&test.list);
添加节点
添加节点一般有两个接口:dlist_add和dlist_add_tail
static inline void __dlist_add(struct dlist *entry, struct dlist *prev, struct dlist *next)
{
entry->next = next;
entry->prev = prev;
next->prev = entry;
prev->next = entry;
}
/* Add a new entry to the head of list */
static inline void dlist_add(struct dlist *list, struct dlist *entry)
{
__dlist_add(entry, list, list->next);
}
/* Add a new entry to the tail of list */
static inline void dlist_add_tail(struct dlist *list, struct dlist *entry)
删除节点
删除节点调用dlist_del接口
static inline void __dlist_del(struct dlist *entry)
{
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
}
/* Delete an entry from list */
static inline void dlist_del(struct dlist *entry)
{
__dlist_del(entry);
entry->next = NULL;
entry->prev = NULL;
}
遍历节点
遍历节点有dlist_for_each和dlist_for_each_entry,两者的区别参考:
linux之list_for_each和list_for_each_entry函数 - 裸睡的猪 - 博客园
dlist_for_each
dlist_for_each_entry
还有一个是安全遍历,在删除节点的时候使用。不使用这个接口的话,不能直接对链表进行操作,只能读取
dlist_for_each_entry_safe
通常我们要自定义一个结构体,然后结构体中包含 struct list_head
。list_head
本质上就是链表中的一个节点,而且是一个 通用节点结构,用来把自己的结构体组织成链表。可以把 struct list_head
理解为“钩子”,用来将节点一个个挂到链表上
参考: