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

2024-09-05 23:12

本文主要是介绍linux下c语言中的单向列表,双向链表,内核双向列表,及适用场景,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

这篇关于linux下c语言中的单向列表,双向链表,内核双向列表,及适用场景的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140334

相关文章

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta