Linux内核之数据结构--链表

前言

Linux内核实现了一下常用的内建数据结构,主要有:

  • 链表
  • 队列
  • 映射
  • 二叉树

今天详细学习一下链表的知识,链表是一种存放和操作可变数量元素(常称为节点)的数据结构。Linux内核的标准链表就是采用环形双向链表形式实现的。

链表数据结构

传统的链表是将数据存放在链表节点中;而Linux内核的方式与众不同,它的链表节点只有两个指针(prev和next),链表节点保存在用户数据结构中。
链表代码在头文件< linux/list.h>中声明,数据结构很简单:

struct list_head 
{
    struct list_head *next;
    struct list_head *prev;
}

next指针指向下一个链表节点,prev指向上一个链表节点。然后这个链表节点list_head一般保存在数据的结构体内:

struct fox
{
    unsigned long      tail_length;         //尾巴长度
    unsigned long      weight;              //重量
    bool               is_fantastic;        //狐狸是否奇妙?
    struct list_head   list//链表节点存放在此处
}

这样在以后对链表的操作都是针对链表节点list_head进行的,然后根据list_head就可以找到其所在的数据结构,这是通过list_entry()函数实现的:

list_entry(ptr,type,member);
/*
ptr是指向list_head类型的链表的指针
type是数据的结构体,struct fox
member是数据结构体中的一个域,类型为list_head
函数的作用就是根据结构的成员指针找到其所在结构体的指针。
*/

声明和初始化一个链表

Linux提供了两种方式初始化链表。
一种是使用LIST_HEAD()这个宏:

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)

LIST_HEAD(fox_list);就是定义并初始化了名为fox_list的链表,链表头为fox_list,其next、prev指针都指向自己。

另一种是先定义list_head指针变量,然后用INIT_LIST_HEAD()将其初始化为链表:

struct fox *red_fox;
red_fox=kmalloc(sizeof(*red_fox),GFP_LERNEL);
red_fox->tail_length=40;
red_fox->weigth=6;
red_fox->is_fantastic=false;
INIT_LIST_HEAD(&red_fox->list);//注意参数为指针

添加和删除节点

向链表中添加一个节点:

list_add(struct list_head *new, struct list_head *head);
例:
list_head(&fox->list, &fox_list);
//fox是新建的数据结构体,fox_list是之前初始化的链表

把节点增加到链表尾:

list_add_tail(struct list_head *new, struct list_head *head);

从链表中删除一个节点:

list_del(struct list_head *list);
例:
list_del(&fox->list);

注意,该删除操作并不会释放list或包含list的结构体所长用的内存。仅仅是将其从链表中移除。
从链表中删除一个节点并对其初始化:

list_del_init(struct list_head *list);

把节点从一个链表移动到另一个链表:

list_move(struct list_head *list, struct list_head *head);
//把list项从链表中移除,并添加到另一个链表的head节点后面

把节点从一个链表移动到另一个链表的末尾:

list_move_tail(struct list_head *list, struct list_head *head);

检查链表是否为空:

list_empty(struct list_head *head);

若链表为空返回非0值,否则返回0。
合并两个链表:

list_splice(struct list_head *list, struct list_head *head);
list_splice_init(struct list_head *list, struct list_head *head);
//合并后初始化原来的链表

将list指向的链表插入到指定的链表head节点后面。

遍历链表

最简单的方法就是使用list_for_each()宏遍历链表,再通过list_entry()获取完整数据结构体
例:

struct list_head *p;
struct fox *f;
list_for_each(p, &fox_list)
{
    f=list_entry(p, struct fox, list);
}

以上两个函数可以合并为一个:list_for_each_entry()

struct fox *f;
list_for_each_entry(f, &fox_list, list)
{
    //f就遍历了所有的数据结构体;
}

反向遍历链表:

list_for_each_entry_reverse(pos, head, member);

遍历的同时安全删除节点:

list_for_each_entry_safe(pos, next, head, member);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值