Linux链表

http://blog.csdn.net/jsyao/article/details/7818817

对于链表,我想每一个程序员都很了解。结构就像一根链条一样,一节接一节,而对它的访问有点像冰糖葫芦,如果你要吃第二个,你必须先吃掉第一个。这就是单向链表。当然它也有更高级的,比如,循环链表,双向链表,双向循环链表。Linux内核的标准链表就是环形双向循环链表。
       Linux中的链表有点特殊,它没有头节点,它的尾节点就直接指向首节点。于是构成了一个很大的环,所以每一个节点都是头节点,你可以从任意节点出发,沿任意的方向循环访问链表或者是它的一部分。
       Linux内核中的链表是很优秀的设计,内核中所欲用到链表的地方都使用了它,所以在你的代码中也最好用这些已有的链表接口,别螳臂挡车,阻挡潮流了。
      下面我们来看看Linux内核中的链表给我们提供了什么样的功能。
      首先,链表结构体定义在头文件<linux/list.h>中,形式很简单:
      struct list_head {
                struct list_head *next, prev;
      };
     一个list_head结构体本身没有什么意义,,通常需要把它嵌入到你自己的结构体中:
     struct my_struct {
              struct list_head list;
              unsigned long dog;
              void *cat;
     };
     链表在使用前必须初始化,由于多数元素都是动态创建(也许这就是你需要使用链表的原因),所以最常见的情况是在运行时初始化链表。
     struct my_struct *p;
     p->dog = 0;
     p->cat = NULL;
     INIT_LIST_HEAD(&p->list);
    
     直接声明和初始化一个静态链表:
     static LIST_HEAD(fox);
     上述语句声明并初始化名为fox的静态链表。
     不需要与任何链表的内部成员打交到,你仅仅将链表结构插入到你自己的数据中就可以了。
操作链表    内核提供了一组函数来操作链表,这些函数都要使用一个或多个list_head结构体指针做参数。因为函数都是用C语言以内联函数形式实现的,所以它们的原型都在头文件<linuxlist.h>中。
     有趣的是,所有这些函数的复杂度都是O(1),也就是说,无论这些函数操作的链表大小如何,无论它们得到额参数如何,它们都在恒定的时间里完成。
1,给链表增加一个节点:在给定节点之后
     list_add(struct list_head *new, struct list_head *head)
2,给链表增加一个节点:在给定节点之前
    list_add_tail(struct list_head *new, struct list_head *head)
3,从链表删除一个节点:
    lsit_del(struct list_head *entry)
需要自己手动释放entry结构体
4,从链表中删除一个节点,并对其进行重新初始化
    lsit_del_init(struct list_head *entry)
5,把节点从一个链表移到另一个链表:
    list_move(struct list_head *list, struct list_head *head)
    list_move_tail(struct list_head *list, struct list_head *head)
6,检查链表是否为空:
    lsit_empty(struct list_head *head)
    如果指定的链表为空,该函数返回非0值,否则返回0
7,合并两个链表
    list_splice(struct list_head *list, struct list_head *head)
    list_splice_init(struct list_head *list, struct list_head *head)
如果你已经得到了next和prev指针,那你可以使用内部操作函数,从而省下提领指针的时间,内部函数与外部函数重名,只是在前面加了两条下划线。
遍历链表:
内核给我们提供了一组非常好用的接口来遍历链表,不过它们的复杂度为O(n),n为链表中的元素数目。list_for_each()宏就是用来遍历链表,它有两个参数,第一个用来指向当前项,第二个是需要遍历的链表,但是它得到的只是lsit_head的指针,而我么您需要的是插入了list_head的结构体。list_entry()宏可以帮助我们它有三个参数,一个是指 向给定的链表元素的指针,一个是其中嵌入了链表的结构体类型的引用,另一个是 结构体中链表成员的名称:如下是用法:
       struct list_head *p;
       struct my_struct * my;
       list_for_each(p, &mine->list) {
             my = list_entry(p, struct my_struct, list);
       }
还有一些宏:list_for_each_prev()      list_for_each_safe()  可以选择使用
最后一个宏只能用来防止链表删除操作,为了防止并发访问实际的链表数据,应该使用其他的锁

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值