linux 内核链表解析2

来源:互联网 发布:lol数据分析 编辑:程序博客网 时间:2024/05/22 12:53

我用一个程序来说明在struct person 中增加了struct list_head 变量后怎么来操作这样的双向链表。

 

[cpp] view plaincopyprint?
  1. #include <stdio.h>   
  2. #include "list.h"   
  3. struct person   
  4. {   
  5.     int age;   
  6.     int weight;   
  7.     struct list_head list;   
  8. };   
  9. int main(int argc, char* argv[])   
  10. {   
  11.     struct person *tmp;   
  12.     struct list_head *pos, *n;   
  13.     int age_i, weight_j;   
  14.     // 定义并初始化一个链表头   
  15.     struct person person_head;   
  16.     INIT_LIST_HEAD(&person_head.list);   
  17.        
  18.     for(age_i = 10, weight_j = 35; age_i < 40; age_i += 5, weight_j += 5)   
  19.     {   
  20.         tmp =(struct person*)malloc(sizeof(struct person));   
  21.         tmp->age = age_i;   
  22.         tmp->weight = weight_j;   
  23.         // 把这个节点链接到链表后面   
  24.         // 这里因为每次的节点都是加在person_head的后面,所以先加进来的节点就在链表里的最后面   
  25.         // 打印的时候看到的顺序就是先加进来的就在最后面打印   
  26.         list_add(&(tmp->list), &(person_head.list));   
  27.     }   
  28.     // 下面把这个链表中各个节点的值打印出来   
  29.     printf("/n");   
  30.     printf("=========== print the list ===============/n");   
  31.     list_for_each(pos, &person_head.list)   
  32.     {   
  33.         // 这里我们用list_entry来取得pos所在的结构的指针   
  34.         tmp = list_entry(pos, struct person, list);   
  35.         printf("age:%d,  weight: %d /n", tmp->age, tmp->weight);   
  36.     }   
  37.     printf("/n");   
  38.     // 下面删除一个节点中,age为20的节点   
  39.     printf("========== print list after delete a node which age is 20 ==========/n");   
  40.     list_for_each_safe(pos, n, &person_head.list)   
  41.     {   
  42.         tmp = list_entry(pos, struct person, list);   
  43.         if(tmp->age == 20)   
  44.         {   
  45.             list_del_init(pos);   
  46.             free(tmp);   
  47.         }   
  48.     }   
  49.     list_for_each(pos, &person_head.list)   
  50.     {   
  51.         tmp = list_entry(pos, struct person, list);   
  52.         printf("age:%d,  weight: %d /n", tmp->age, tmp->weight);   
  53.     }   
  54.     // 释放资源  
  55.     list_for_each_safe(pos, n, &person_head.list)   
  56.     {   
  57.         tmp = list_entry(pos, struct person, list);   
  58.         list_del_init(pos);   
  59.         free(tmp);   
  60.     }   
  61.        
  62.     return 0;   
  63. }  

 

编译:

 

linux 下的 可以:gcc -g -Wall main.c -o test

windows 下的可以建一个控制台工程,把main.c 和list.h 加到工程中编译。

 

运行test 后的输出如下:

=========== print the list ===============

age:35, weight: 60

age:30, weight: 55

age:25, weight: 50

age:20, weight: 45

age:15, weight: 40

age:10, weight: 35

 

========== print list after delete a node which age is 20 ==========

age:35, weight: 60

age:30, weight: 55

age:25, weight: 50

age:15, weight: 40

age:10, weight: 35

 

我们看到,这就是一个非常好和有效的双向链表,我们不需要为每一种结构去定义相关的函数,如遍历、增加和删除等函数,我们只需要简单的在结构中增加struct list_head 的一个变量,我们的结构立马就变成了一个双向链表,而且,我们对链表的操作也不用自己写,直接调用已经定义好的函数和宏,一切就那么简单和有效。

 

文章写到这里是不是应该结束了呢,没有,我还不想结束,还想在继续说。

 

四、 一个结构多个链表

 

在上面,我们看到人的结构是这样的:

struct person

{

int age;

int weight;

struct list_head list;

};

 

它的链表图形看起来如下图所示:

但我们知道,一个人,他的熟悉还有很多,例如他有各种各样的衣服,各种不同的鞋子等。所以,我定义了两个这样的结构:

 

struct clothes

{

int size; // 衣服有各种大小

Color color; // 衣服有各种颜色,这里假设有一种 Color 的类型

};

 

struct shoot

{

Kind kind; // 鞋子有各种类型,秋、冬、运动、休闲等,同样假设已经定义过 Kind 这样的类型

Color color; // 鞋子也有各种颜色

};

 

那么这个人的定义可能就是这样的:

struct person

{

int age;

int weight;

struct clothes clo;

struct shoot sht;

};

 

在这里,我有意 clo  sht 这两个变量放在 list 后面,其实,代表链表的 list 在结构中的位置在哪里是没什么关系的, list_entry 也一样可以将结构的指针找出来。

 

这里有一个问题是,一个人不止一件衣服,也不止一双鞋子,所以我们应该把他拥有的衣服和鞋子应该加上,那么怎么加呢?这里应该把衣服和鞋子的结构也变成链表,这不就解决了。

 

把结构改一下,变成了这样:

 

struct clothes

{

struct list_head list;

int size; // 衣服有各种大小

Color color; // 衣服有各种颜色,这里假设有一种 Color 的类型

};

 

struct shoot

{

struct list_head list;

Kind kind; // 鞋子有各种类型,秋、冬、运动、休闲等,同样假设已经定义过 Kind 这样的类型

Color color; // 鞋子也有各种颜色

};

 

现在鞋子和衣服都是链表了,都可以把它们连接起来。那我们的结构是不是还应该这样定义:

struct person

{

int age;

int weight;

struct clothes clo;

struct shoot sht;

};

 

如果是,那么我们应该怎么定义这个头节点。在前面我们看到,定义一个 person_head 的头节点是这样的:

 

// 定义并初始化一个链表头

struct person person_head;

INIT_LIST_HEAD (&person_head.list);

 

难道我们应该这样定义吗?

 

// 定义并初始化一个链表头

struct person person_head;

INIT_LIST_HEAD (&person_head.list);

INIT_LIST_HEAD (&person_head.col.list);

INIT_LIST_HEAD (  person_head.sht.list);

 

那么增加一件衣服进去呢,代码看起来是这样的:

 

 

struct clothes tmp =(struct clothes*)malloc(sizeof(struct clothes));

...

list_add(&(tmp->list), &(person_head.clo.list));

 

这样会不会有点麻烦,其实,如果我们可以认真想一想,我们会发现,既然 struct peron 是一个含有 list_head 的结构,它可以把它的类型节点链接在后面,那么 struct clothes 也是一个含有 list_head 的结构,它们本质也没什么区别,应该也可以链接在它后面的。所以我们的 struct person 的结构应该变成这样:

struct person

{

int age;

int weight;

struct list_head clo;

struct list_head sht;

};

 

那么我们链接节点后的图形如下图所示:

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

由上面,我们可以知道,有了 struct list_head 结构,我们可以为我们的结构体增加多个子节点链表。

 

0 0
原创粉丝点击