Chinaunix首页 | 论坛 | 博客
  • 博客访问: 716886
  • 博文数量: 67
  • 博客积分: 994
  • 博客等级: 准尉
  • 技术积分: 1749
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-03 14:10
文章分类
文章存档

2014年(11)

2013年(14)

2012年(14)

2011年(28)

分类: LINUX

2011-09-27 17:24:24

在讲list.h前,我们必须对链表有一个大体了解。
      首先链表是一种存放和操作可变数量元素的数据结构。链表和数组有何不同?他们的不同之处在于,链表所包含的元素都是动态创建的,在编译时,不必知道具体需要创建多少个元素,另外也因为链表的每个元素的创建时间各不相同,所以他们在内存中无需占用连续的内存空间。
        链表存放数据的理想情况是:需要遍历所有数据或需要动态加入和删除数据。
         链表分为单链表,双链表和循环链表。简单说下单链表就是其域中只有一个指针域。
        当然我现在分析的是循环双链表。
        1、链表的初始化
#define LIST_HEAD_INIT(name) { &(name), &(name) }
 
 #define LIST_HEAD(name)     struct list_head name = LIST_HEAD_INIT(name)
 
 static inline void INIT_LIST_HEAD(struct list_head *list)
 {
         list->next = list;
        list->prev = list;
 }上面分别使用宏和函数实现了链表的初始化,至于里面的inline函数,我上一篇已做了分析。
2、链表节点的定义
     struct list_head
{
         struct list_head *prev, *next;
}
从其函数名就可以看出链表没有“头节点”,因为其是双向的,任何一个节点都可以做头节点。
3、相关链表的插入操作,对节点的插入操作,在我们做起来就是通过写个代码实现,没神嘛,但是不觉得再在插入的基础上出现什么头插,尾插。是不是我们都要写?看牛人写代码就是不一样,人家使用了内部函数,实现了代码的重复利用率。
static inline void __list_add(struct list_head *new,
                                struct list_head *prev,
                                struct list_head *next)
  {
         next->prev = new;
          new->next = next;
          new->prev = prev;
          prev->next = new;
};这就是内部函数,接下来实现头插和尾插就很方便了。
头插:实现了栈操作
static inline void list_add(struct list_head *new, struct list_head *head)
  {
          __list_add(new, head, head->next);
  }
尾插:实现了队操作
static inline void list_add_tail(struct list_head *new, struct list_head *he    ad)
  {
          __list_add(new, head->prev, head);
  }
4、接下来是节点的删除(也使用了内部函数)
static inline void __list_del_entry(struct list_head *entry)
 {
         __list_del(entry->prev, entry->next);
 }


static inline void list_del(struct list_head *entry)
 {
         __list_del(entry->prev, entry->next);
}
对节点的删除,内核并没有回收删除节点的数据结构所占用的内存,而是仅仅将其从链表中移走。
好了,链表的基本操作大体介绍了。现在如何遍历链表?
内核提供了list_for_each()宏来实现链表的遍历,具体原型如下:
#define list_for_each(pos, head) \
         for (pos = (head)->next; prefetch(pos->next), pos != (head); \
                pos = pos->next)

其中head是已经定义并初始化的一个数据结构体。(切记)
链表的初始化:
首先定义一个数据结构体
struct datainfo
{
   int num;
   struct list_head list;
};
做动态初始化:
struct datainfo *head;
head->num=0;
INIT_LIST_HEAD (&head->list);
有了遍历函数,如何通过list_head成员访问到它所在数据结构中其他数据?
list_entry()宏就实现了这样的操作。
#define list_entry(ptr, type, member)       container_of(ptr, type, member)
其中ptr指向list_head的指针,type是定义的数据结构,member则是数据结构定义中list_head的成元变量名。
具体实现如下:
struct  list_head *p;
struct  datainfo *data;
list_for_each(p,data->list)
{
   data=list_entry(p,struct datainfo,list);
}
自此,一个链表基本就分析完了。当然链表中还有其他操作,我只介绍了几种常用操作。




阅读(1029) | 评论(0) | 转发(0) |
0

上一篇:一个简单程序

下一篇:浅谈进程

给主人留下些什么吧!~~