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

来源:互联网 发布:淘宝买电动车哪家 编辑:程序博客网 时间:2024/06/15 23:39

前言

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 foxmember是数据结构体中的一个域,类型为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);
0 0
原创粉丝点击