【脚踢数据结构】内核链表

news2024/9/24 5:31:01
  • (꒪ꇴ꒪ ),Hello我是祐言QAQ
  • 我的博客主页:C/C++语言,Linux基础,ARM开发板,软件配置等领域博主🌍
  • 快上🚘,一起学习,让我们成为一个强大的攻城狮!
  • 送给自己和读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏

        内核链表(Kernel Linked List)是操作系统内核中常用的一种数据结构,用于管理和维护一系列数据元素(节点)。它也是一种线性数据结构,其中每个节点包含了数据元素本身以及指向下一个节点的指针。内核链表在操作系统中广泛应用于管理进程、文件描述符、内存分配等诸多场景。

一、内核链表概述

        内核链表通常由一个特定的数据结构定义,该数据结构包含一个或多个指向链表中首个和最后一个节点的指针,以及其他用于操作和管理链表的属性。在C语言中,内核链表的定义示例:

//数据
typedef int Datatype;

//节点(大结构体)
typedef struct Kernel_node
{
	Datatype data;			//数据域
	struct kernel_list list;	//指针域
}k_node;

//指针节点(小结构体)
struct kernel_list {
    struct kernel_list *prev;//前驱指针
    struct kernel_list *next;//后继指针
};


        kernel_list结构体定义了一个内核链表的节点,其中prev指向前一个节点,next指向下一个节点,这一点在某种意义上与常规的双向循环链表一致,但是还是有区别的。我们再来看看之前所学习的双向循环链表的节点定义:

//数据
typedef int Datatype;

//节点
typedef struct Node
{
	DataType data;		//数据域
	struct Node *prev;	//指针域:前驱指针
	struct Node *next;	//指针域:后继指针
}node;

        这样一对比,就会发现常规链表与内核链表最大的区别就是嵌套,内核链表的节点结构通常嵌套在某个容器数据结构中,可以理解为能单独对指针域进行操作,而不影响数据。

 所以这也暴露了常规链表的缺陷:

        (1)每一种应用中,节点都是特殊的,导致每一条链表都是特殊的,因此每一种链表的增删查改这些算法也都是特殊的;

        (2)当一个节点处于变化的数据结构网络中的时候,节点指针无法指向稳定不变的节点。

        这样的描述或许不能让你有直观的感觉,但当你往下看,真正去理解了内核链表再回过头来,你就会豁然开朗。

二、内核链表的原理

        内核链表的节点结构通常嵌套在某个容器数据结构中,以实现紧密关联。节点结构中至少包含两个指针,一个指向前一个节点,一个指向后一个节点。这样的设计使得在链表中插入、删除节点的操作更加高效,无需像数组那样移动大量元素。我们可以这样理解:

        (1)将链表的结构抽象出来,去除节点中的具体数据,只保留逻辑的双向指针,形成一条只包含逻辑的“纯粹的链表”。

        (2)将链表“寄宿”于具体的数据节点之中,使他贯穿这些节点,可以借助一定的方式通过“纯粹链表“的指针域得到数据节点。

            内核链表做到了将数据和逻辑(指针)分开,在红色方框内的这样只有前后两指针的链表形式被称为Linux标准双向循环链表

三、内核链表的操作

        在学习内核链表的操作之前,我们先要来了解一下list.h文件。list.h 是一个常见的头文件,通常用于实现内核链表(双向链表)的相关功能。在 Linux 内核中,list.h 提供了一种高效的方式来操作链表,包括插入、删除、遍历等操作。完整的该文件可从网上各处找到,接下来我们将只举例用到的结构体。

1. 节点声明

//数据
typedef int Datatype;

//链表节点(大结构体)
typedef struct Kernel_node
{
	Datatype data;			//数据域
	struct list_head list;	//指针域
}k_node;

         list_head 是在list.h中已经定义好的指针域部分,我们可以将其称之为小结构体,用它来构建“纯粹链表”。


 struct list_head {
 	struct list_head *next, *prev;
 };

2.初始化链表

//初始化链表
k_node *init_kernel_list()
{
	k_node *head = malloc(sizeof(k_node));
	if (head==NULL)
	{
		perror("malloc");
		exit(0);
	}
	else
	{		
		INIT_LIST_HEAD(&(head->list));//带参宏,初始化小结构体里面的这两个指针成员

	}
	return head;
}

        INIT_LIST_HEAD也是list.h中已经定义好的带参宏,原型如下:

#define INIT_LIST_HEAD(ptr) do { \
	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

3.创建节点

//创建节点
k_node *create_kernel_node(Datatype data)
{
	k_node *new = malloc(sizeof(k_node));
	if (new != NULL)
	{
		new->data = data;
		new->list.next = NULL;
		new->list.prev = NULL;
	}
	return new;
}

4.遍历链表


//遍历链表
void display(k_node *head)
{
	struct list_head *pos = NULL;
	k_node *Node = NULL;
	list_for_each(pos, &(head->list))
	{
		Node = list_entry(pos, k_node, list);
		printf("%d ", Node->data);
	}
	printf("\n");
}

        其中list_for_each和list_entry也是在list.h中定义好的带参宏:


//遍历链表的for循环,每一次循环体内得到的就是一个小结构体指针
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next)


//小结构体指针ptr,大结构体类型type,小结构体在大结构体内部的成员名
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

        做完这些操作,我们就可以通过一个实例来验证我们的操作是否正确,我们可以创建一个10个节点的链表并打印。

         实例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "list.h"

//数据
typedef int Datatype;

//链表节点
typedef struct Kernel_node
{
	Datatype data;			//数据域
	struct list_head list;	//指针域
}k_node;

//初始化链表
k_node *init_kernel_list()
{
	k_node *head = malloc(sizeof(k_node));
	if (head==NULL)
	{
		perror("malloc");
		exit(0);
	}
	else
	{
		INIT_LIST_HEAD(&(head->list));
	}
	return head;
}

//创建节点
k_node *create_kernel_node(Datatype data)
{
	k_node *new = malloc(sizeof(k_node));
	if (new != NULL)
	{
		new->data = data;
		new->list.next = NULL;
		new->list.prev = NULL;
	}
	return new;
}

//遍历链表
void display(k_node *head)
{
	struct list_head *pos = NULL;
	k_node *Node = NULL;
	list_for_each(pos, &(head->list))
	{
		Node = list_entry(pos, k_node, list);
		printf("%d ", Node->data);
	}
	printf("\n");
}

int main(int argc, char const *argv[])
{
	k_node *head = init_kernel_list();
	for (int i = 0; i < 10; ++i)
	{
		k_node *new = create_kernel_node(i+1);

		//插入节点到链表
		list_add_tail(&(new->list), &(head->list));
	}

	//遍历链表
	display(head);

	return 0;
}

(未完待续...)

四、今日总结

        与一般链表相比,内核链表有一些特点和优势:

        1.容器结构体: 在内核链表中,节点通常嵌套在某个数据结构中,这个数据结构即所谓的容器结构体。这种设计可以让数据元素和链表节点紧密关联,方便数据的操作和管理。

        2.稳定性和预测性: 内核链表在操作系统内核中广泛应用,而且内核链表的实现通常被优化为在各种情况下都能够稳定和预测地工作,不容易受到异常情况的影响。

        3.特定操作: 内核链表通常提供一系列针对特定操作的函数,如插入、删除、遍历等。这些函数经过精心的设计和优化,能够高效地处理链表操作。

        总之,内核链表是操作系统内核中的一种重要数据结构,用于高效地管理各种资源和数据。它与一般链表相比,更注重稳定性和性能优化,以满足操作系统的特定需求。

        更多C语言Linux系统ARM板实战数据结构相关文章,关注专栏:

   手撕C语言

            玩转linux

                    脚踢数据结构

                            6818(ARM)开发板实战

📢写在最后

  • 今天的分享就到这啦~
  • 觉得博主写的还不错的烦劳 一键三连喔~
  • 🎉感谢关注🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/854779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【iOS安全】开启任意app的WebView远程调试

参考&#xff1a;https://mp.weixin.qq.com/s/bNKxQaVrPaXsZ5BPbsXy7w &#xff08;来自周智老师的公众号&#xff09; 概述 Safari 有一个内置的前端调试器&#xff0c; 在iPhone通过局域网或者USB连接MacBook 并启用Safari 远程调试之后&#xff0c;前端调试器默认情况下对…

【机器学习1】什么是机器学习机器学习的重要性

什么是机器学习? 简而言之&#xff0c;机器学习就是训练机器去学习。 机器学习作为人工智能(Artificial Intelligence,AI)的一个分支&#xff0c;以其最基本的形式来使用算法通过从数据中获取知识来进行预测。 不同于人类通过分析大量数据手动推导规则和模型&#xff0c;机…

释放AI创作潜能:从大模型训练到高产力应用

文章目录 每日一句正能量前言什么是人工智能生成内容&#xff08;AIGC&#xff09;人工智能生成内容&#xff08;AIGC&#xff09;能做什么为什么要用人工智能生成内容&#xff08;AIGC&#xff09;创作成果用Java实现冒泡排序算法学生信息收集系统学生请假管理系统需求分析教务…

SpringBoot 依赖管理

Spring Boot 依赖管理 1. 父项目做依赖管理 无需关注版本号&#xff0c;自动版本仲裁机制 <!-- 依赖管理 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version&g…

利用 PHP 特性绕 WAF 测试

在测试绕过 WAF 执行远程代码之前&#xff0c;首先构造一个简单的、易受攻击的远程代码执行脚本&#xff0c;内容如图&#xff1a; 第 6 行是一个比较明显的命令执行代码&#xff0c;第 3 行尝试拦截 system、exec 或 passthru 等函数&#xff08;PHP 中有许多其他函数可以执行…

CTF REVERSE练习之脱壳分析

今天要介绍脱壳分析的实验。壳&#xff0c;在自然界中&#xff0c;植物用壳来保护种子&#xff0c;动物用壳来保护身体等。同样&#xff0c;在一些计算机软件里也有一段专门负责保护软件不被非法修改或反编译的程序。他们附加在原程序上通过Windows加载器载入内存后&#xff0c…

FreeRTOS(任务管理的创建、删除、挂起、恢复)

目录 一、任务的基本概念 二、任务状态的概念 1、Running—运行态&#xff1a; 2、Ready—就绪态 3、Blocked—阻塞态 4、Suspended—挂起态 三、任务状态的切换 四、系统启动 1、vTaskStartScheduler()函数 1.1 作用 1.2 启动函数介绍 2、空闲任务 2.1 空闲任务的作…

mac安装vscode 配置git

1、安装vscode 官网地址 下载mac稳定版安装很慢的解决办法 (转自) mac电脑如何解决下载vscode慢的问题 选择谷歌浏览器右上角的3个点&#xff0c;选择下载内容&#xff0c;右键选择复制链接地址&#xff0c;在新窗口粘贴地址&#xff0c; 把地址中的一段替换成下面的cscode.sd…

新的里程碑!纪念正月十六工作室博客总访问量突破两百万

时值盛夏&#xff0c;清风徐徐&#xff0c;不觉间我们的博客访问量又迈入了新的里程碑——访问量突破两百万&#xff01; 总访问量突破百万&#xff1a; 个人成就&#xff1a; 记得上次突破重大里程碑还是去年夏天&#xff0c;那时我们重修岳阳楼&#xff0c;追往忆&#…

小程序商品如何设置阶梯价?

阶梯价在电商小程序中是一种常见的销售策略&#xff0c;可以吸引更多的消费者并提高销售额。下面将介绍一些怎么设置小程序产品的阶梯价的方法。 1. 添加/修改商品的时候&#xff0c;点击阶梯价&#xff0c;会弹出阶梯价设置界面。 2. 设置阶梯价规则。例如&#xff0c;当消费者…

http相关知识点

文章目录 长链接http周边会话保持方案1方案2 基本工具postmanFiddlerFiddler的原理 长链接 一张网页实际上可能会有多种元素组成&#xff0c;这也就说明了网页需要多次的http请求。可由于http是基于TCP的&#xff0c;而TCP创建链接是有代价的&#xff0c;因此频繁的创建链接会…

gSpan算法执行步骤详解示例

目录 1. 问题描述2. gSpan算法步骤2.1 数据预处理2.2 深度递归挖掘频繁子图2.2.1 获取所有的频繁边2.2.2 深度递归挖掘频繁子图 参考文献 1. 问题描述 gSpan 是一款图规则挖掘算法&#xff0c;目标是从现有的图集中挖掘频繁子图。如下图中包含三个图&#xff1a; 其中圆圈为顶…

centos安装python3的多个版本

标题 原本安装了python3.6&#xff0c;但是又有一个项目需要py3.7&#xff0c;所以需要让两个版本共存 操作 1、下载py3.7 wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz2、解压 tar -xzvf Python-3.7.3.tgz进入到文件夹 cd Python-3.7.33、安装 本人c…

【Go 基础篇】Go语言初探:第一段代码与执行过程解析

介绍 Go语言&#xff08;也称为Golang&#xff09;作为一门现代化的编程语言&#xff0c;以其简洁的语法、高效的性能和丰富的标准库而受到了广泛关注和使用。对于初学者来说&#xff0c;编写和执行第一段Go代码是迈向这门语言的重要一步。本篇博客将带您深入了解Go语言的第一…

BLE蓝牙协议栈分析

BLE——协议层次结构 一、BLE Controller Controller实现射频相关的模拟和数字部分&#xff0c;完成最基本的数据发送和接收&#xff0c;Controller对外接口是天线&#xff0c;对内接口是主机控制器接口HCI&#xff08;Hostcontroller interface&#xff09;&#xff1b; 控制…

46.利用matlab绘制维安尼曲线(matlab程序)

1.代码 clear close all syms s t k u r; x12*sin(s)*cos(t);y12*sin(s)*sin(t);z12*cos(s); x2-2*cos(k)*cos(k);y22*sin(k)*cos(k);z2u; subplot(1,2,1);ezmeshc(x2,y2,z2,[0,pi,-2,2]); %绘制圆柱面 hold on; ezsurf(x1,y1,z1,[-pi,pi,0,pi]); %绘制球面 title( 球面与圆柱…

SpringBoot--发邮件的方法(有示例)

原文网址&#xff1a;SpringBoot--发邮件的方法(有示例)_IT利刃出鞘的博客-CSDN博客 简介 本文介绍SpringBoot发邮件的方法(有示例)。 依赖 pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-ma…

nginx简介与安装配置,目录结构和配置文件介绍

一.nginx简介 1.简介 2.特性 二.nginx安装 1.rpm包方式 &#xff08;1&#xff09;下载扩展源 &#xff08;2&#xff09;安装扩展rpm包&#xff0c;nginx -V查看配置参数&#xff0c;后面源码安装时要用到 2.源码方式 &#xff08;1&#xff09;建议提前下好所需要的部…

C语言系列之原码、反码和补码

一.欢迎来到我的酒馆 讨论c语言中&#xff0c;原码、反码、补码。 目录 一.欢迎来到我的酒馆二.原码 二.原码 2.1在计算机中&#xff0c;所有数据都是以二进制存储的&#xff0c;但不是直接存储二进制数&#xff0c;而是存储二进制的补码。原码很好理解&#xff0c;就是对应的…

Python读取excel数据并创建文件目录树-全解析过程及逻辑

需求描述&#xff1a; 需要将以下excel内的结构解析&#xff0c;并创建对应的文件目录 实现思路&#xff1a; 实现思路是通过解析Excel文件中的目录结构&#xff0c;并根据目录结构创建对应的文件夹。 具体的实现步骤如下&#xff1a; 1. 加载指定的Excel文件&#xff0c…