Chinaunix首页 | 论坛 | 博客
  • 博客访问: 12677
  • 博文数量: 7
  • 博客积分: 190
  • 博客等级: 入伍新兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-02 22:20
文章分类

全部博文(7)

文章存档

2012年(7)

最近访客

分类: LINUX

2012-08-13 09:44:03

注意:
1.以下代码除了说明的,一般都取自include/linux/list.h
2.内核版本为:2.6.32-71.29.1.el6.i686

一.链表数据结构的实现:

注意一点:在定义链表时,必须定义不带数据的头结点,然后让头指针指向它。在后面的遍历都是基于这点考虑的。
内核采用的双向循环链表,将指针域封装成一个结构体:
  1. struct list_head {
  2.      struct list_head *next, *prev;
  3. };
使用时直接将这个结构体与所要用到的数据放在一块组成一个结构体。

二.相关函数
1.声明和初始化
linux源代码中初始化结构体时,一般都会先把右值用宏定义出来,然后再赋值。我认为主要是想让代码可读性增强
  1. #define LIST_HEAD_INIT(name) { &(name), &(name) }
  2.  
  3.   #define LIST_HEAD(name) \
  4.   struct list_head name = LIST_HEAD_INIT(name)
  5.  
  6.  static inline void INIT_LIST_HEAD(struct list_head *list)
  7.  {
  8.    list->next = list;
  9.    list->prev = list;
  10.  }


2.插入/删除
    2.1插入
链表的插入根据插入的位置分为头插法和尾插法。先定义了一个可以在链表任意节点插入的函数,
然后再调用这个函数实现头插和尾插。

  1. static inline void __list_add(struct list_head *new,
  2.                   struct list_head *prev,
  3.                   struct list_head *next)
  4. {
  5.     next->prev = new;
  6.     new->next = next;
  7.     new->prev = prev;
  8.     prev->next = new;
  9. }
头插:
  1. static inline void list_add(struct list_head *new, struct list_head *head)
  2. {
  3.     __list_add(new, head, head->next);
  4. }

尾插:
  1. static inline void list_add_tail(struct list_head *new, struct list_head *head)
  2. {
  3.     __list_add(new, head->prev, head);
  4. }



    2.2删除

  1. static inline void __list_del(struct list_head * prev, struct list_head * next)
  2. {
  3.     next->prev = prev;
  4.     prev->next = next;
  5. }

注意要将删除节点的指针域指向特定值LIST_POISON1和LIST_POISON2,防止对entry的访问。
  1. static inline void list_del(struct list_head *entry)
  2. {
  3.     __list_del(entry->prev, entry->next);
  4.     entry->next = LIST_POISON1;
  5.     entry->prev = LIST_POISON2;
  6. }


 
3.遍历
3.1根据list_head获得结点的地址:
链表中仅仅给出的一个结点的list_head的地址,如何通过list_head的地址获得结点的地址,
从而获得数据域中的值呢?

  1. #define list_entry(ptr, type, member) \
  2.     container_of(ptr, type, member)
//取自include/linux/kernel.h文件中
  1. #define container_of(ptr, type, member) ({ \
  2.     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  3.     (type *)( (char *)__mptr - offsetof(type,member) );})



3.2遍历宏
  1. #define list_for_each(pos, head) \
  2.     for (pos = (head)->next; prefetch(pos->next), pos != (head); \
  3.             pos = pos->next)
有了list_for_each(),为什么还用定义list_for_each_safe()呢?
原因是当删除节点时,节点的next会被改变为一个固定值,下次遍历将产生错误。所以还需要一个指针来保存下一个节点指针。

  1. #define list_for_each_safe(pos, n, head) \
  2.     for (pos = (head)->next, n = pos->next; pos != (head); \
  3.         pos = n, n = pos->next)
三.不足
  1. 链表的操作中还有像合并,移动的操作,这些就等到真正要用时再看一下吧。
  2.哈希表没有列出来
四.参考资料


阅读(363) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~