linux下c语言中的单向列表,双向链表,内核双向列表,及适用场景

news2024/11/15 19:28:42

1. 单向链表(Singly Linked List)

1.1 定义与结构
单向链表是链式存储结构中最简单的一种。它的每个节点包含两个部分:
- 数据域:存储数据元素
- 指针域:存储指向下一个节点的指针

在单向链表中,节点通过指针域相互链接,形成一个线性结构。链表的最后一个节点指向 `NULL`,表示链表的结束。

C 语言中单向链表的定义:

struct Node {
    int data;          // 数据域
    struct Node *next; // 指针域,指向下一个节点
};

1.2 操作与实现

插入节点
插入节点通常有几种方式:
- 在链表头插入节点
- 在链表尾插入节点
- 在链表中的某个位置插入节点

在链表头插入节点的代码示例:

void insert_at_head(struct Node **head, int new_data) {
    struct Node *new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = *head;
    *head = new_node;
}
 

删除节点
删除节点同样可以根据位置(头节点、尾节点、中间节点)来进行操作。

删除指定值节点的代码示例:

void delete_node(struct Node **head, int key) {
    struct Node *temp = *head, *prev;

    if (temp != NULL && temp->data == key) {
        *head = temp->next; // 如果头节点就是要删除的节点
        free(temp);
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return; // 如果没有找到该节点

    prev->next = temp->next; // 解除该节点与链表的链接
    free(temp);
}
 

遍历链表
遍历链表是通过一个临时指针从头到尾遍历所有节点。

遍历链表的代码示例:

void print_list(struct Node *node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}
 

1.3 适用场景
单向链表适合用于需要频繁在表头插入或删除元素的场景,例如:
- 实现堆栈(栈顶元素可以快速插入和删除)
- 需要动态增加或删除元素且对内存要求敏感时

然而,由于单向链表只能向一个方向遍历,查找和插入某些特定位置的性能较差。

2. 双向链表(Doubly Linked List)

2.1 定义与结构
双向链表相比单向链表,增加了对每个节点前驱节点的引用。每个节点包含三个部分:
- 数据域:存储数据
- 前驱指针域:指向上一个节点
- 后继指针域:指向下一个节点

C 语言中双向链表的定义:

struct Node {
    int data;
    struct Node *prev; // 前驱指针
    struct Node *next; // 后继指针
};
 

2.2 操作与实现
由于双向链表的节点有两个指针,操作和单向链表相比稍显复杂,但在链表的遍历、删除和插入操作中,灵活性更强。

插入节点
在链表头插入节点:

void insert_at_head(struct Node **head, int new_data) {
    struct Node *new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = *head;
    new_node->prev = NULL;

    if (*head != NULL) {
        (*head)->prev = new_node;
    }

    *head = new_node;
}
 

删除节点
删除指定节点:

void delete_node(struct Node **head, struct Node *del_node) {
    if (*head == NULL || del_node == NULL) return;

    if (*head == del_node) *head = del_node->next;

    if (del_node->next != NULL) del_node->next->prev = del_node->prev;

    if (del_node->prev != NULL) del_node->prev->next = del_node->next;

    free(del_node);
}
 

遍历链表
双向链表可以从任意节点向前或向后遍历,提供了更灵活的遍历方式。

从头到尾遍历双向链表的代码:

void print_list(struct Node *node) {
    struct Node *last;
    printf("Traversal in forward direction: ");
    while (node != NULL) {
        printf("%d -> ", node->data);
        last = node;
        node = node->next;
    }
    printf("NULL\n");

    printf("Traversal in reverse direction: ");
    while (last != NULL) {
        printf("%d -> ", last->data);
        last = last->prev;
    }
    printf("NULL\n");
}
 

2.3 适用场景
双向链表特别适用于需要双向遍历的场景,例如:
- 实现双端队列(Deque)
- 实现导航系统,用户可以前后移动(如浏览器的前进/后退操作)

双向链表的缺点是每个节点需要额外的空间来存储 `prev` 指针,相比单向链表占用更多内存。

3. 内核双向链表(Linux Kernel Doubly Linked List)

3.1 定义与结构
在 Linux 内核中,双向链表的实现采用了高度模块化和通用化的设计。Linux 内核中的双向链表不会直接与数据绑定,而是通过一个独立的 `list_head` 结构体表示链表节点的指针。这使得链表可以灵活地嵌入任意数据结构中。

Linux 内核双向链表的定义:

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

每个节点的数据存储在包含 `list_head` 的外部数据结构中。

3.2 操作与实现
内核提供了一套高效的宏和函数来简化双向链表的操作。例如:
- *`INIT_LIST_HEAD(&head)`:初始化链表头节点。
- `list_add()` 和 `list_add_tail()`:在链表头或尾部插入节点。
- `list_del()`:删除节点。

插入节点示例

struct my_data {
    int value;
    struct list_head list;
};

struct list_head my_list;
INIT_LIST_HEAD(&my_list);

struct my_data data1 = { .value = 1 };
list_add(&data1.list, &my_list);
 

遍历节点示例
使用宏遍历链表中的每个节点:

struct my_data *entry;
list_for_each_entry(entry, &my_list, list) {
    printk(KERN_INFO "Value: %d\n", entry->value);
}
 

3.3 适用场景
Linux 内核双向链表广泛用于内核中的各种模块,例如:
- 实现任务队列
- 管理内核资源
- 设备驱动程序中的资源管理

内核双向链表特别适合场景复杂、需要高度通用性和高效链表操作的场合。

4. 总结与比较

5. 选择建议
- 单向链表:适合于内存受限、操作简单、只需要单向遍历的场景,如堆栈、队列。
- 双向链表:适合需要双向遍历、插入和删除频繁的场景,如双端队列、双向导航应用。
- 内核双向链表:适用于高效链表操作、复杂系统管理场景,尤其是嵌入式系统、内核模块和驱动开发。

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

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

相关文章

OpenHarmony实战开发:@Watch装饰器:状态变量更改通知

往期鸿蒙全套实战精彩文章必看内容: 鸿蒙开发核心知识点,看这篇文章就够了 最新版!鸿蒙HarmonyOS Next应用开发实战学习路线 鸿蒙HarmonyOS NEXT开发技术最全学习路线指南 鸿蒙应用开发实战项目,看这一篇文章就够了&#xff08…

为什么要做智慧厕所,智慧公厕的建设意义有哪些?@卓振思众

智慧厕所是利用物联网、大数据、人工智能等技术,对传统厕所进行智能化升级改造后的新型厕所。它具备环境监测与调控、厕位引导、资源管理、安全管理、数据分析与管理平台等功能和特点。卓振思众是智慧厕所源头厂家,建设智慧厕所主要有以下几个重要原因&a…

【python因果推断库7】使用 pymc 模型的工具变量建模 (IV)2

目录 与普通最小二乘法 (OLS) 的比较 应用理论:政治制度与GDP 拟合模型:贝叶斯方法 多变量结果和相关性度量 结论 与普通最小二乘法 (OLS) 的比较 simple_ols_reg sk_lin_reg().fit(X.reshape(-1, 1), y)print("Intercept:", simple_ols_…

V90总线伺服报800F错误

1、博途PLC工艺对象位置轴轴控功能块 博途PLC工艺对象位置轴轴控功能块(完整SCL代码)-CSDN博客文章浏览阅读423次。S7-1200PLC脉冲轴位置轴位置控制功能块S7-1200PLC脉冲轴位置轴位置控制功能块优化(完整SCL源代码)_s71200 脉冲轴-CSDN博客文章浏览阅读341次。该博客详细介绍了…

自闭症儿童语言干预

自闭症儿童的语言发展往往面临独特挑战,这不仅影响了他们的日常交流能力,也制约了其社交与认知的全面发展。因此,实施科学有效的语言干预对于促进自闭症儿童的语言能力至关重要。 语言干预应基于个性化原则,充分考虑每个孩子的兴…

基于echarts车辆大数据综合分析平台

0.序言 基于ECharts的大数据综合分析平台技术框架与基本原理 技术框架 基于ECharts的大数据综合分析平台是一个集数据收集、处理、分析及可视化展示于一体的综合性系统。其技术框架主要可以分为以下几个层次: 数据源层: 数据收集:通过各种…

STM32F407ZET6

GPIO SPI 串行外设接口(Serial Peripheral Interface)的简称也叫做SPI,是一种高速的、全双工同步通信的一种接口,串行外设接口一般是需要4根线来进行通信(NSS、MISO、MOSI、SCK),但是如果打算实现单向通信(最少3根线,NSS、MOSI、SCK),就可以利用这种机制实现一对多或…

八、发票校验(1)

第一节 发票知识 1、发票介绍 发票是指一切单位和个人在购销商品、提供或接受服务以及从事其他经营活动中,所开具和收取的业务凭证,是会计核算的原始依据,也是审计机关、税务机关执法检查的重要依据。 发票必须具备的要素是根据议定条件由…

Xilinx系FPGA学习笔记(四)VIO、ISSP(Altera)及串口学习

系列文章目录 文章目录 系列文章目录VIO(Vivado)ISSP(Altera)串口学习FPGA串口发送FPGA串口接收 VIO(Vivado) VIO 的全称叫 Virtual Input/Output,建立一个虚拟的输入/输出信号,可以…

CRE6959AM70V055S 超低待机功耗反激式开关电源芯片

CRE6959AM70V055S 是一款高度集成的电流型 PWM控制 IC,为高性能、低待机功率、低成本、高效率的隔离型反激式开关电源控制器。在满载时,CRE6959AM70V055S工作在固定频率(65kHz)模式。在负载较低时,CRE6959AM70V055S采用节能模式,实…

前端XSS 攻击与SQL注入 处理

前端XSS 攻击与SQL注入 处理 文章目录 前端XSS 攻击与SQL注入 处理 一、XSS 攻击与SQL注入是什么二、XSS 攻击与SQL注入包含哪些方式1. XSS 攻击方式2. SQL 注入方式 三、如何避免XSS 攻击与SQL注入1. 避免XSS 攻击2. 避免SQL 注入 四、扩展与高级技巧1. XSS 防御策略2. SQL 注…

代码随想录算法训练营第32天 动态规划part01| 题目:理论基础 、 509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯

代码随想录算法训练营第32天 动态规划part01| 题目:理论基础 、 509. 斐波那契数 、70. 爬楼梯 、 746. 使用最小花费爬楼梯 文章来源:代码随想录 理论 题目名称:509. 斐波那契数 斐波那契数,通常用 F(n) 表示,形成的…

【论文分享】GPU Memory Exploitation for Fun and Profit 24‘USENIX

目录 AbstractIntroductionResponsible disclosure BackgroundGPU BasicsGPU architectureGPU virtual memory management GPU Programming and ExecutionGPU programming modelGPU kernelDevice function NVIDIA PTX and SASSSASS instruction encoding GPU Memory SpacesGlob…

react购物车Redux

入口index.js import React from react import {createRoot} from react-dom/clientimport App from ./App //注入store import {Provider} from "react-redux"; import store from "./store";const root createRoot(document.getElementById(root)) roo…

Python系统教程003

变量的数据类型 将输入信息存入变量name中然后输出。 如果想通过键盘输 入信息再存入变量 中应该怎么办? 一、内容 input函数变量的数据类型变量的运算 (一)、input函数 1、input函数1 函数:用来完成某一个特定功能的代码 …

2.第二阶段x86游戏实战2-认识进制、理解数据宽度和位的概念

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 工具下载: 链接:https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

NXP,S32K1XX汽车通用微控制器开发笔记

文章目录 1. 概述2. 开发环境配置2.1 S32 Design Studio2.2 安装SDK2.3 新建demo工程2.4 字体配置2.5 按需求修改demo2.5.1 修改pin脚定义2.5.2 增加串口打印功能2.6 编译代码2.7 debuger 配置参考1. 概述 S32K1系列32位微控制器(MCU)提供基于Arm Cortex-M的MCU,以及基本的…

某PO手机市场竞争分析,巧用波特五力分析法找出核心竞争力!

某PO手机主要从事手机的生产与销售,最近推出了新款 Reno 系列 5G 手机。当前,苹果占据了高端市场,华为占据了中高端市场,而某 PO 手机则在剩余市场中与某 VO 和某米竞争。近年来,某 PO手机凭借中端 R 系列逐步取得市场…

【文献阅读】AdaLora: Adaptive Budget Allocation for Parameter-Efficient Fine-Tuning

目录 1. 前言2. 矩阵分解2.1 SVD分解2.2 特征值分解2.3 LU分解2.4 QR分解 3. AdaLora3.1 motivation3.2 改进 1. 前言 矩阵分解为什么可以加速推理 假设原始权重矩阵 W ∈ R ( m ∗ n ) {W∈R^{(m*n)}} W∈R(m∗n),矩阵乘法中时间复杂度为mn,变形为 W …

Vue.js 组件化开发:父子组件通信与组件注册详解

Vue.js 组件化开发:父子组件通信与组件注册详解 简介: 在 Vue.js 的开发中,组件是构建应用的重要基础。掌握组件的创建与使用,尤其是父子组件的通信和组件的注册与命名,是开发中不可或缺的技能。本文将详细探讨这些内容…