C链表的一些基础知识

一、链表的基本概念

链表是一种常见的线性数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针(单链表情况)。通过指针将各个节点连接起来,与数组不同,链表在内存中的存储不是连续的,其优点是可以灵活地进行插入、删除操作,无需像数组那样移动大量元素。

二、单链表的实现

  1. 定义节点结构体
// 定义单链表节点结构体
typedef struct ListNode {
    int data;  // 数据域,这里以整型数据为例,可根据需求修改类型
    struct ListNode *next;  // 指针域,指向下一个节点
} ListNode;
  1. 创建链表节点函数
// 创建一个新的链表节点
ListNode *createNode(int value) {
    ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        return NULL;
    }
    newNode->data = value;
    newNode->next = NULL;
    return newNode;
}

  1. 插入节点(尾插法为例)
// 尾插法向链表插入节点
void insertTail(ListNode **head, int value) {
    ListNode *newNode = createNode(value);
    if (*head == NULL) {
        *head = newNode;
    } else {
        ListNode *temp = *head;
        while (temp->next!= NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

  1. 遍历链表函数

// 遍历链表并输出节点数据
void traverseList(ListNode *head) {
    ListNode *current = head;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

  1. 释放链表内存函数
// 释放链表占用的内存
void freeList(ListNode *head) {
    ListNode *current = head;
    ListNode *next;
    while (current!= NULL) {
        next = current->next;
        free(current);
        current = next;
    }
}

三、双链表的实现

  1. 定义双链表节点结构体
// 定义双链表节点结构体
typedef struct DoublyListNode {
    int data;
    struct DoublyListNode *prev;  // 指向前一个节点的指针
    struct DoublyListNode *next;  // 指向后一个节点的指针
} DoublyListNode;

  1. 创建双链表节点函数
// 创建双链表节点
DoublyListNode *createDoublyNode(int value) {
    DoublyListNode *newNode = (DoublyListNode *)malloc(sizeof(DoublyListNode));
    if (newNode == NULL) {
        printf("内存分配失败!\n");
        return NULL;
    }
    newNode->data = value;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

  1. 插入节点(尾插法为例)
// 尾插法向双链表插入节点
void insertTailDoubly(DoublyListNode **head, int value) {
    DoublyListNode *newNode = createDoublyNode(value);
    if (*head == NULL) {
        *head = newNode;
    } else {
        DoublyListNode *temp = *head;
        while (temp->next!= NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
        newNode->prev = temp;
    }
}

  1. 遍历双链表(正向)函数
// 正向遍历双链表并输出节点数据
void traverseDoublyListForward(DoublyListNode *head) {
    DoublyListNode *current = head;
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

  1. 遍历双链表(反向)函数
// 反向遍历双链表并输出节点数据
void traverseDoublyListBackward(DoublyListNode *head) {
    DoublyListNode *current = head;
    if (current == NULL) return;
    while (current->next!= NULL) {
        current = current->next;
    }
    while (current!= NULL) {
        printf("%d ", current->data);
        current = current->prev;
    }
    printf("\n");
}

  1. 释放双链表内存函数
// 释放双链表占用的内存
void freeDoublyList(DoublyListNode *head) {
    DoublyListNode *current = head;
    DoublyListNode *next;
    while (current!= NULL) {
        next = current->next;
        free(current);
        current = next;
    }
}

四、循环链表

  1. 循环单链表
    循环单链表与普通单链表的区别在于,其最后一个节点的指针不是指向 NULL,而是指向链表的头节点,形成一个环形结构。在实现插入、遍历等操作时,需要注意循环的终止条件有所不同,例如遍历循环单链表时,判断节点是否回到头节点来结束循环。
  2. 循环双链表
    循环双链表中,头节点的 prev 指针指向尾节点,尾节点的 next 指针指向头节点,构成双向循环结构。其操作函数在处理边界情况和指针修改时要考虑这种循环特性,比如插入节点时要正确更新节点间的双向指针关系。

五、链表的常用操作及函数总结

  • 创建节点:用于生成新的链表节点,分配内存并初始化数据和指针域。
  • 插入节点:可以有头插法、尾插法、按位置插入等多种方式,调整链表节点间的指针连接关系来插入新节点。
  • 删除节点:根据节点的值或者位置等条件,找到要删除的节点,并妥善处理其前后节点的指针连接,释放对应节点内存。
  • 遍历链表:按顺序访问链表中的每个节点,输出节点数据或者进行其他需要逐个节点处理的操作,单链表通常是单向遍历,双链表可实现双向遍历。
  • 查找节点:依据给定的条件(如节点值等)在链表中查找满足条件的节点,返回节点指针或者相关索引等信息。

六、链表的应用场景

  • 动态数据存储:当需要频繁地插入、删除元素,且元素数量不确定时,链表比数组更合适,比如实现一个简单的任务队列管理系统。
  • 多项式表示与运算:可以用链表来存储多项式的各项系数和指数,方便进行多项式的加法、乘法等运算。
  • 操作系统中的进程管理:用于管理进程控制块(PCB)链表,方便对进程进行调度、插入新进程、结束进程等操作。

总之,链表在 C 语言编程中是非常重要的数据结构,熟练掌握其实现和各种操作函数,能帮助更好地解决很多实际编程问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

服务器日志自动上传到阿里云OSS备份

背景 公司服务器磁盘空间有限,只能存近15天日志,但是有时需要查看几个月前的日志,需要将服务器日志定时备份到某个地方,需要查询的时候有地方可查。 针对这个问题,想到3个解决方法: 1、买一个配置比较低…

使用 vllm 部署 MiniCPM-o 2.6

使用 vllm 部署MiniCPM-o 2.6 1. 创建虚拟环境2. 克隆代码3. 从代码安装 vllm4. 安装 flash-attn5. 启动 MiniCPM-o 2.66. 使用 chatbox 客户端访问并测试一下 1. 创建虚拟环境 conda create -n vllm_openbmb python3.11 -y conda activate vllm_openbmb 2. 克隆代码 git clo…

JavaScript笔记基础篇04——对象

黑马程序员视频地址:黑马程序员前端JavaScript入门到精通全套视频教程https://www.bilibili.com/video/BV1Y84y1L7Nn?vd_source0a2d366696f87e241adc64419bf12cab&spm_id_from333.788.videopod.episodes 目录 对象 对象的基本使用 1.对象声明语法 2.对象…

Autosar CP RTE规范解读之不同 BSW 接口的通知与软件组件激活机制:标准化接口与 AUTOSAR 接口的实现方式

在汽车电子系统开发中,特别是在遵循 AUTOSAR 架构的系统中,基本软件(BSW)模块之间的通信和信息通知机制至关重要,它直接影响着系统的性能、可靠性以及各个软件组件之间的协同工作能力。本文根据不同类型的 BSW 接口&am…

利用大语言模型进行长文本抽取式摘要的突破

论文地址:https://arxiv.org/pdf/2408.15801v1 引言:信息过载时代的文本摘要需求 在信息爆炸的时代,如何从海量文本中快速提取关键信息成为了一项至关重要的技能。自动文本摘要技术应运而生,主要分为抽取式和生成式两种方法。生成…

Quick get started with vcpkg, windows visual studio | CPP

本文属于 C 系列文章,本篇文章,是在 Quickstart C with cmake, visualstudio | CPP 基础上,继续的。 目录 vcpkg总结安装安装 mingw64安装 vcpkg 创建项目查询已有的包在 Visual Studio 中调试发布依赖Trouble ShootingCMake Error: CMake wa…

《Linux服务与安全管理》| 邮件服务器安装和配置

《Linux服务与安全管理》| 邮件服务器安装和配置 目录 《Linux服务与安全管理》| 邮件服务器安装和配置 1.在Server01上安装dns、postfix、dovecot和telnet,并启动 2.在Server01上配置DNS服务器,设置MX资源记录 3.在server1上…

BGP分解实验·9——路由聚合与条件性通告(1)

路由聚合是有效控制缩减BGP路由表的方法之一,路由聚合的前提和IGP一样,需要有路由目标存在BGP表中,与IGP不同的是,BGP路由聚合可以定义按需抑制路由的能力。 实验拓扑如下所示: 现在开始把从R1的R5的基础配置先准备好…

Spring Boot 配置(官网文档解读)

目录 摘要 Spring Boot 配置加载顺序 配置文件加载顺序 Spring Boot 配置加载方式 Value Value 注解简单示例 ConfigurationProperties 启动 ConfigurationProperties ConfigurationProperties 验证 ConfigurationProperties 与 Value 对比 Autowired Autowired 自…

ElasticSearch JavaRestClient查询之快速入门

文章目录 查询操作流程概述构建并发起请求1. 创建请求对象2. 设置请求体3. 发送请求 查询结果的解析1. 解析结果结构2. 获取总条数3. 获取命中的数据 完整示例代码总结 查询操作流程概述 Elasticsearch 查询操作大致可以分为两个部分: 构建并发起请求:…

【C++】红黑树的应用(封装map和set)

✨ 青山一道同云雨,明月何曾是两乡 🌏 📃个人主页:island1314 🔥个人专栏:C学习 🚀 欢迎关注:👍点赞 &…

C# 给定欧氏平面中的一组线可以形成的三角形的数量

给定欧氏平面中的一组线可以形成的三角形的数量(Number of Triangles that can be formed given a set of lines in Euclidean Plane) 给定欧氏平面上的 n 条不同直线的集合 L {l 1 , l 2 , ………, l n }。第i 条直线由形式为 a i x b i y c i的方程给出。求出可以使用集合…

C++书籍 第一部分专业C++程序设计概述

1&#xff0c;必不可少的“hello world” #include<iostream>int main(int argc, char** argv) {std::cout << "hello world" << std::endl;return 0; } 这个是一个极其简单的程序&#xff0c;虽然没有多大简直&#xff0c;但是可以体现c程序格式方…

leetcode刷题记录(七十二)——146. LRU 缓存

&#xff08;一&#xff09;问题描述 146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09;146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类&#xff1a; * LRUCache(int capacity)…

微调时如何平衡新旧参数?

在微调预训练模型时&#xff0c;平衡新旧参数是一个重要的问题。合理地平衡新旧参数可以确保模型既保留预训练阶段学到的通用表示能力&#xff0c;又能够有效地适应特定任务。以下是一些常用的方法和技术来平衡新旧参数&#xff1a; ### 1. 学习率调整 **不同层使用不同的学习…

性能调优篇 四、JVM运行时参数

目录 一、三种JVM参数选项1、标准参数选项1&#xff09;特点2&#xff09;各种选项3&#xff09;-server 和 -client 2、-X参数选项3、-XX参数选项 二、添加JVM参数选项1、idea 如何添加jvm参数 三、常见的JVM参数选项1、打印设置的参数选项及其值2、堆、栈、方法区等内存大小设…

2024年博客之星主题创作|Android 开发:前沿技术、跨领域融合与就业技能展望

目录 引言 一、推动 Android 应用创新的核心力量 1.1 人工智能与机器学习的崛起 1.2 增强现实&#xff08;AR&#xff09;与虚拟现实&#xff08;VR&#xff09;的应用扩展 1.3 5G技术的推动 1.4 跨平台开发技术的成熟 1.4.1 React Native 1.4.2 Flutter 1.4.3 Taro …

汇编与逆向(一)-汇编工具简介

RadASM是一款著名的WIN32汇编编辑器&#xff0c;支持MASM、TASM等多种汇编编译器&#xff0c;Windows界面&#xff0c;支持语法高亮&#xff0c;自带一个资源编辑器和一个调试器。 一、汇编IDE工具&#xff1a;RadASM RadASM有内置的语言包 下载地址&#xff1a;RadASM asse…

Gin 源码概览 - 路由

本文基于gin 1.1 源码解读 https://github.com/gin-gonic/gin/archive/refs/tags/v1.1.zip 1. 注册路由 我们先来看一段gin代码&#xff0c;来看看最终得到的一颗路由树长啥样 func TestGinDocExp(t *testing.T) {engine : gin.Default()engine.GET("/api/user", f…

Linux网络序列化与反序列化

Linux网络序列化与反序列化 1. 前言 在网络通信中&#xff0c;互相通信的信息不一定都是字符串&#xff0c;往往一些结构化的信息也需要进行通信。理论上&#xff0c;只要服务器和客户端都自定义一个共同的协议&#xff0c;结构化的信息也能实现正常通信。但考虑到不同系统、…