首页 > 其他分享 >数据结构内核链表的代码

数据结构内核链表的代码

时间:2024-08-05 10:26:54浏览次数:14  
标签:node head struct list 链表 内核 数据结构 data

说明

内核链表的诞生原因呢,就是为了把数据域和指针域分开来

就形成了下面这样的链表

struct list
{
    struct list *prev; //存放前缀节点的指针
    struct list *next; //存放后缀节点的指针
};

那有的读者会疑问,那数据放哪里?

//节点结构体
struct node
{
    // 以整型数据为例
    //数据域
    int data; 

    //指针域
    struct list_head list; //小结构体,里面有两个结构体指针

};

同样的道理,我们创建一个含有数据域的结构体,并且这个结构体包含了内核链表头文件的自带的结构体类型list_head;然后他们的关系就形成了下面这个图

在上面这个图里面,我们就只需要创建大结构体,而小结构体在list.h里面已经有了。

1.申请一个节点

//节点初始化 -- 在堆空间申请一个struct node结构体大小,并对成员进行初始化
struct node *init_node(void)
{
    //在堆空间开辟sizeof(struct node)大小空间--大结构体
    struct node *new = (struct node *)malloc(sizeof(struct node));
    if(new == NULL)
    {
        printf("malloc fail\n");
        return NULL;
    }

  

    new->data = 0;
    
    //小结构体里面是两个指针,两个指针指向自己,形成双向循环循环
    //手写初始化代码
    // new->list.prev = &new->list;
    // new->list.next = &new->list;

    //使用内核链表API进行初始化小结构体
    //传入小结构体的地址
    INIT_LIST_HEAD(&new->list);


    return new;
}

2.创建链表

申请完节点就可以创建链表啦,一句代码就可以创建。

struct node *head = init_node();

3.插入数据

插入数据的时候就不用自己封装函数啦,直接调用头文件提供的,如下

new = init_node();//生成节点
if(new == NULL)
{
   printf("节点生成失败,请重新操作\n");
   break;
}
printf("节点地址:%p\n", new);

printf("请输入数据:");
scanf("%d", &new->data);

//节点插入链表头
list_add(&new->list, &head->list);

很多观众可以不是很清楚,这两个参数表示什么意思,下面我们来看看头文件里的介绍

在这个函数里,可以看到参数的类型要求是struct list_head *类型,也就是小结构体。所以我们要传入的是大结构体里面的小结构体的地址。所以要给new->list取地址。

可以看到整个插入函数是插入在头节点后面的。当然还有插入到头节点前面的

4.查找数据

当我们查找数据的时候,往往要遍历数据,这时候内核链表又给我们提供了遍历链表的函数,在下面这个查找数据的函数中,用到了那个遍历链表的函数

struct node * find_data_in_list(struct node *head, int find_data)
{
    struct node *tmp = NULL;
    struct list_head *pos = NULL;

    list_for_each(pos, &head->list)
    {
        //通过小结构体得到大结构体地址
        tmp = list_entry(pos, struct node, list);
        if(tmp->data == find_data)
        return tmp;
    }
    return NULL;
}

我们看看遍历链表函数在内核链表中的解释

注释这里说到,pos是用来表示遍历内核链表时的位置。head是传入头节点。

这里注释还有说到,不安全的遍历方式,这个不安全的遍历方式是指,他遍历的过程中,没有把下一个位置的保存起来,而安全的遍历方式是会保存起来的。下面是安全的遍历

可以看到,他有一个n来保存下一个位置。如果删除所有指定的数据时,不使用安全的遍历方式,容易造成段错误,在下面删除就用到了这个安全的遍历方式。

那还有一个问题,list_entry这个函数是干嘛的呢?是这样的

我们在遍历时传入的数据全都是小结构体的地址,所以当我们要获取数据时,就得获取大结构体的地址,才可以访问到大结构体的数据域,因此我们就要利用这个函数,通过传入小结构体地址来获取大结构体的地址。

5.删除数据

这个函数是删除所有值为del_data节点的数据

void delete_data_int_list(struct node *head, int del_data)
{
    struct node *tmp = NULL;
    struct list_head *pos = NULL;
    struct list_head *n = NULL;

    list_for_each_safe(pos, n, &head->list)
    {   
        tmp = list_entry(pos, struct node, list);
        if(tmp->data == del_data)
        {
            list_del(&tmp->list); 
            free(tmp);
        } 
    }
}

然后删除函数也不用我们去封装

在这个函数,我们只要传入小结构体的地址,就可以删除这个节点了。是不是很方便

6.修改数据

int modify_data(struct node *head,int find_data, int data)
{
    int flag = 0;
    struct node *tmp = NULL;
    struct list_head *pos = NULL;

    list_for_each(pos, &head->list)
    {
        //通过小结构体得到大结构体地址
        tmp = list_entry(pos, struct node, list);
        if(tmp->data == find_data)
        {
            tmp->data = data;
            flag = 1;
        }
    }
    return flag;
}

经过了上面的知识,修改数据就比较简单了,总的来说就是,传入小结构体遍历链表,获取大结构体的地址,通过判断每一个大结构体的数据域是否是要修改的数据。

结束语

差不多了,那个list.h里面还有很多好用的函数,大家可以去看看,有移动的,判断是否为空的,合并两条链表的。把他们运用熟练起来的话,那就很厉害了。

标签:node,head,struct,list,链表,内核,数据结构,data
From: https://blog.csdn.net/m0_62978644/article/details/140874950

相关文章

  • (链表基础)PTA习题11-8 单链表结点删除
    题目要求:本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中所有存储了某给定值的结点删除。链表结点定义如下:structListNode{intdata;ListNode*next;};函数接口定义:structListNode*readlist();structListNode*deletem(structListNode*L,......
  • c语言数据结构单链表中随机链表的复制
    c语言数据结构单链表中随机链表的复制文章目录c语言数据结构单链表中随机链表的复制1.随机链表的复制问题2.解决思路3.代码的实现1.随机链表的复制问题给你一个长度为nn......
  • 数据结构 - 并查集基础
    ......
  • 链表part02
    今天是8月3日,学习了链表的第二部分。交换链表两个节点,考察对next的操作和tmp的灵活运用。删除链表的倒数第N个节点,双指针减少遍历次数。链表相交,移动链表尾对齐,其实就是动长链表的指针。环形链表,记住方法。4.24交换链表两个节点题目:给你一个链表,两两交换其中相邻的节点,并......
  • 内核简介
    Linux内核基础楔子这部分的内容首先要回忆一下计算机的基础知识,基本的计算机结构包括CPU(算数逻辑单元ALU、控制单元CU)、存储器、输入和输出。CPU和其它设备是通过总线连接的。CPU执行的基础被称为指令集,CPU执行存储器存取指令时:CPU发出存取信号,然后就从存储器存取数据。存取器通......
  • 数据结构——数列分块 学习笔记
    数据结构——数列分块学习笔记下面部分代码使用,usingll=longlong;#defineintll基础思想问题引入问题:实现区间加;区间求和。基本结构引用经典东西,我们考虑构造一个结构,形如,那么,结论是,复杂度证明为什么块长一般是\(\sqrtn\)呢?我们假设构造的块长是\(......
  • 数据结构:链表经典算法OJ题
    目录前言一、移除链表元素二、反转链表三、合并两个有序链表四、链表的中间节点五、环形链表的约瑟夫问题前言  在了解了链表的相关知识后,我们还需要一些题目进行练习加深对链表这方面知识的理解,也可以用来检测链表这块学的的怎么样,废话不多说,开始上手。一、移......
  • 算法题之旋转链表
    旋转链表给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。示例1:输入:head=[1,2,3,4,5],k=2输出:[4,5,1,2,3]示例2:输入:head=[0,1,2],k=4输出:[2,0,1]提示:链表中节点的数目在范围 [0,500] 内-100<=Node.val<=1000<=k<=......
  • Java常用类和数据结构与算法
    1.其他常用类1.1.Math类java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值一般为double型。如果需要更加强大的数学运算能力,可以使用apachecommons下面的Math类库publicclassTestMath{publicstaticvoidmain(String[]args){S......
  • 数据结构之特殊矩阵的压缩存储
    1.对称矩阵的压缩存储定义:若n阶矩阵A满足a(ij)=a(ji)(1≤i,j≤n),则称A为n阶对称矩阵。压缩存储方法:由于对称矩阵上三角和下三角的元素相同(主对角线上的元素只存储一次),因此可以只存储上三角(或下三角)的元素和主对角线上的元素。存储方式:通常使用一维数组来存储这些元素。......