顺序表与链表·续
引言
本文承接上文(顺序表与链表-CSDN博客),开始对链表的要点提炼。前文提到顺序表适合需要频繁随机访问且数据量固定的场景,而链表适合需要频繁插入和删除且数据量动态变化的场景。链表的引入弥补了顺序表在动态性和操作效率上的不足,是线性表的重要实现方式之一。
链表
概念
分类
链表的分类可以根据以下维度进行:
-
单向或双向:决定节点的指针数量和遍历方向。
-
带头或不带头:决定是否有额外的头节点简化操作。
-
循环或不循环:决定链表是否形成环。
通过组合这些维度,可以设计出适合不同场景的链表结构。例如:
-
带头单向循环链表:适合实现队列。
-
带头双向循环链表:适合需要双向遍历且操作简化的场景。
而我们常遇到的主要是不带头单向非循环链表和带头双向循环链表(以下图例分别对应这两种链表)
实现
无头单向非循环链表的简单实现
//"slist.h"
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLTDateType;typedef struct SListNode
{SLTDateType data;struct SListNode* next;
}SListNode;// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->data = x;newnode->next = NULL;return newnode;
}// 单链表打印
void SListPrint(SListNode* plist)
{SListNode* cur = plist;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{SListNode* newnode = BuySListNode(x);if (*pplist == NULL) {*pplist = newnode;}else{SListNode* tail = *pplist;while (tail->next!=NULL){tail = tail->next;}tail->next = newnode;}}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{SListNode* newnode = BuySListNode(x);newnode->next = *pplist;*pplist = newnode;}// 单链表的尾删
void SListPopBack(SListNode** pplist)
{assert(pplist);assert(*pplist);//一个节点if ((*pplist)->next == NULL) {free(*pplist);*pplist = NULL;}//多个节点SListNode* tail = *pplist;while (tail->next->next!=NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
void SListPopFront(SListNode** pplist) {// 防御性检查:拦截非法输入if (pplist == NULL) {fprintf(stderr, "Error: Invalid pointer in SListPopFront\n");return;}// 业务逻辑检查:空链表直接返回if (*pplist == NULL) {return;}SListNode* tmp = *pplist;*pplist = tmp->next;free(tmp);
}// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{SListNode* cur = plist;while (cur) {if (cur->data == x) {return cur;}cur = cur->next;}return NULL;
}
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入? // 因为没有前置指针
// 若要在 pos 之前插入,必须从头节点开始遍历链表找到 pos 的前驱节点,时间复杂度为 O(n)
void SListInsertAfter(SListNode* pos, SLTDateType x)
{if (pos == NULL) return;SListNode* newNode = BuySListNode(x);newNode->next = pos->next;pos->next = newNode;
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置? //删除 pos 节点需要知道其前驱节点,而单链表无法直接获取前驱节点
// 必须从头遍历链表,时间复杂度为O(n),删除 pos 之后的节点只需修改 pos->next,时间复杂度为O(1)。void SListEraseAfter(SListNode* pos)
{if (pos == NULL || pos->next == NULL) return;SListNode* tmp = pos->next;pos->next = tmp->next;free(tmp);
}// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{assert(pphead);assert(pos);assert(*pphead);if (*pphead == pos) SListPushFront(pphead,x);else{SListNode* prev = *pphead;while (prev->next!=pos){prev = prev->next;}SListNode* newnode=BuySListNode(x);prev->next = newnode;newnode->next = pos;}
}// 删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos)
{assert(pphead);assert(*pphead);assert(pos);if (*pphead == pos){// 头删SListPopFront(pphead);}else{SListNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}void SLTDestroy(SListNode** pphead)
{assert(pphead);SListNode* cur = *pphead;while (cur) {SListNode* tmp = cur;cur = cur->next;free(tmp);}*pphead = NULL;
}
关键点说明
-
二级指针的使用:
-
修改头指针时(如插入/删除头节点),需通过二级指针
pplist修改一级指针*pplist。 -
示例:
SListPushFront和SListPopFront直接修改头指针。
-
-
边界条件处理:
-
空链表、单节点链表、尾节点/头节点操作需特殊处理。
-
例如
SListPopBack中需处理链表只有一个节点的情况。
-
-
时间复杂度:
-
头插/头删:O(1)/O(1)
-
尾插/尾删:O(n)/O(n)
-
插入/删除指定位置:平均 O(n)/O(n)(需遍历找到位置)
-
-
内存管理:
-
每次
malloc后需检查内存分配是否成功。 -
删除节点后需及时
free防止内存泄漏。
-
若需要频繁在任意位置前插入或删除,最好使用双向链表,它可以通过前驱指针直接操作,时间复杂度为 O(1)/O(1)。

相关文章:
顺序表与链表·续
引言 本文承接上文(顺序表与链表-CSDN博客),开始对链表的要点提炼。前文提到顺序表适合需要频繁随机访问且数据量固定的场景,而链表适合需要频繁插入和删除且数据量动态变化的场景。链表的引入弥补了顺序表在动态性和操作效率上的…...
nvidia驱动升级-ubuntu 1804
升级 1.从官网下载*.run驱动文件 2.卸载原始驱动 sudo /usr/bin/nvidia-uninstall sudo apt-get --purge remove nvidia-\* # 可能不需要加-\ sudo apt-get purge nvidia-\* # 可能不需要加-\ sudo apt-get purge libnvidia-\* # 可能不需要…...
【Linux】——初识操作系统
文章目录 冯-诺依曼体系结构操作系统shell 冯-诺依曼体系结构 我们现在所使用的计算机就是冯-诺依曼体系结构。 存储器就是内存。 由下图可知,寄存器最快,为啥不用寄存器呢? 因为越快价格就最贵,冯诺依曼体系结构的诞生…...
本地化deepseek
小白都能拥有自己的人工智能 1、我本地环境 系统:win10 cpu:i7(i7-12700),差不多就行 硬盘:500G+2T,可以不用这么大 显卡:七彩虹2060 12G ,够用了 我的配置最高也只能配上8B了, R1模型版本CPUGPU内存存储8B Intel Core i7/AMD Ryzen 7 及以上 无强制要求,有 4…...
利用可变参数模板,可打印任意参数和参数值。(C++很好的调式函数)
很酷的应用: (1) 如何获取可变参数名 代码例子: #define _test(...) (test_t(#__VA_ARGS__, __VA_ARGS__))template<typename... Args> void test_t(const char* names, Args... args) {std::cout << names <<…...
Yashan DB 体系结构
一、体系结构概况 1.1 线程管理 YashanDB采用多线程架构,线程分为两类: • 工作线程(Worker Threads):每个客户端连接到数据库实例时,会创建一个工作线程。工作线程负责处理客户端的SQL请求,执…...
测试工程师Deepseek实战之如何反向PUA它
问: 你是一名资深测试开发工程师 帮我设计一个提效工具,具有以下功能: 1.页面使用PYQT5设计,用两个输入控件,最好是日期类型的控件,第一个日期控件作为开始日期,第二个日期控件作为结束日期;前后…...
Windows系统中在VSCode上配置CUDA环境
前置步骤 安装符合GPU型号的CUDA Toolkit 配置好 nvcc 环境变量 安装 Visual Studio 参考https://blog.csdn.net/Cony_14/article/details/137510909 VSCode 安装插件 Nsight Visual Studio Code Editionvscode-cudacpp 安装 cmake 并配置好环境变量 注:Windows 端…...
React Native 0.76 升级后 APK 体积增大的原因及优化方案
在将 React Native 从 0.71 升级到 0.76 后,打包体积从 40 多 MB 增加到了 80 MB。经过一系列排查和优化,最终找到了解决方案,并将优化过程整理如下。 1. React Native 0.76 体积增大的可能原因 (1) 新架构默认启用 React Native 0.76 默认启用了 New Architecture(新架…...
pycharm找不到conda可执行文件
conda 24.9.2 在pycharm的右下角就可以切换python解释器了...
定时任务框架
常用定时任务框架 JDK 自带的 ScheduledExecutorService 适用于轻量级定时任务,基于线程池实现。API 简单,适用于小规模任务调度。 Quartz 强大的 Java 任务调度框架,支持 Cron 表达式、分布式集群、持久化等。适用于复杂调度场景࿰…...
ESP32S3读取数字麦克风INMP441的音频数据
ESP32S3 与 INMP441 麦克风模块的集成通常涉及使用 I2S 接口进行数字音频数据的传输。INMP441 是一款高性能的数字麦克风,它通过 I2S 接口输出音频数据。在 Arduino 环境中,ESP32S3 的开发通常使用 ESP-IDF(Espressif IoT Development Framew…...
利用后缀表达式构造表达式二叉树的方法
后缀表达式(逆波兰表达式)是一种将运算符放在操作数之后的表达式表示法。利用后缀表达式构造表达式二叉树的方法主要依赖于栈结构。 转换步骤 初始化 创建一个空栈。 遍历后缀表达式 对后缀表达式的每个符号依次处理: 遇到操作数 如果当前符…...
使用express创建服务器保存数据到mysql
创建数据库和表结构 CREATE DATABASE collect;USE collect;CREATE TABLE info (id int(11) NOT NULL AUTO_INCREMENT,create_date bigint(20) DEFAULT NULL COMMENT 时间,type varchar(20) DEFAULT NULL COMMENT 数据分类,text_value text COMMENT 内容,PRIMARY KEY (id) ) EN…...
YOLOv12本地部署教程——42%速度提升,让高效目标检测触手可及
YOLOv12 是“你只看一次”(You Only Look Once, YOLO)系列的最新版本,于 2025 年 2 月发布。它引入了注意力机制,提升了检测精度,同时保持了高效的实时性能。在保持速度的同时,显著提升了检测精度。例如&am…...
SQLAlchemy系列教程:如何防止SQL注入
SQL注入是一种常见的安全漏洞,它允许攻击者通过应用程序的SQL查询操纵数据库。使用ORM工具(如SQLAlchemy)提供的内置功能可以帮助减轻这些风险。本教程将指导您完成保护SQLAlchemy查询的实践。 了解SQL注入 当攻击者能够通过用户输入插入或操…...
1. 树莓派上配置机器人环境(具身智能机器人套件)
1. 安装树莓派系统 镜像下载地址(windows/Mac/Ubuntu),安装Pi5. 2. 环境配置(登录Pi系统) 2.1 启用 SSH From the Preferences menu, launch Raspberry Pi Configuration. Navigate to the Interfaces tab. Select Enable…...
基于SpringBoot的智慧停车场小程序(源码+论文+部署教程)
运行环境 • 前端:小程序 Vue • 后端:Java • IDE工具:IDEA(可自行选择) HBuilderX 微信开发者工具 • 技术栈:小程序 SpringBoot Vue MySQL 主要功能 智慧停车场微信小程序主要包含小程序端和…...
【从零开始学习计算机科学】数字逻辑(九)有限状态机
【从零开始学习计算机科学】数字逻辑(九)有限状态机 有限状态机状态机的表示方法有限状态机的Verilog描述有限状态机 有限状态机(简称状态机)相当于一个控制器,它将一项功能的完成分解为若干步,每一步对应于二进制的一个状态,通过预先设计的顺序在各状态之间进行转换,状…...
HarmonyOS Next~鸿蒙系统ArkCompiler跨平台编译技术的革新实践
HarmonyOS Next~鸿蒙系统ArkCompiler跨平台编译技术的革新实践 引言 在万物互联时代,操作系统对编译技术的需求已从单纯的代码转换演变为跨设备协同、高效资源调度与极致性能优化的综合挑战。华为鸿蒙系统(HarmonyOS)自主研发的ArkCompiler…...
会话管理封装实践:构建安全可扩展的分布式会话系统
1. 项目概述:一个被低估的会话管理利器如果你是一名开发者,尤其是经常需要处理用户登录、权限校验、状态保持这类“脏活累活”的后端或全栈开发者,那么你一定对“会话管理”这四个字又爱又恨。爱的是,它是构建安全、有状态应用的基…...
Wedecode:全平台微信小程序源代码反编译与安全审计终极指南
Wedecode:全平台微信小程序源代码反编译与安全审计终极指南 【免费下载链接】wedecode 全自动化,微信小程序 wxapkg 包 源代码还原工具, 线上代码安全审计,支持 Windows, Macos, Linux 项目地址: https://gitcode.com/gh_mirrors/we/wedeco…...
深度学习训练理论:初始化与梯度消失
深度学习训练理论:初始化与梯度消失 1. 技术分析 1.1 训练挑战概述 深度学习训练面临多种挑战: 训练挑战梯度消失: 梯度趋近于0梯度爆炸: 梯度过大参数初始化: 权重初始化影响激活函数选择: 影响梯度流动1.2 梯度消失原因 原因机制影响激活函数sigmoid/t…...
企业级应用如何通过 Taotoken 统一管理多个团队的模型调用
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 企业级应用如何通过 Taotoken 统一管理多个团队的模型调用 在中大型企业的技术实践中,多个项目组或产品线同时接入和使…...
赛车电气系统设计的现代化转型与实践
1. 赛车电气系统设计的现状与挑战当人们谈论赛车技术时,脑海中浮现的往往是碳纤维车身、空气动力学套件或是大马力发动机。但在这光鲜亮丽的表象背后,电气系统才是现代赛车的"神经系统"。有趣的是,这个关键领域的设计方法却呈现出两…...
基于树莓派与电子墨水屏的慢速电影播放器制作全攻略
1. 项目概述:当电影遇见电子墨水如果你和我一样,对电子墨水(eInk)屏幕那种独特的、像印刷品一样的显示效果着迷,同时又是个喜欢折腾树莓派(Raspberry Pi)的玩家,那么这个项目绝对能让…...
ElevenLabs泰米尔语音部署踩坑实录:DNS解析超时、UTF-8 BOM导致静音、方言ID混淆——97%开发者忽略的3个关键参数
更多请点击: https://intelliparadigm.com 第一章:ElevenLabs泰米尔语音部署踩坑实录:DNS解析超时、UTF-8 BOM导致静音、方言ID混淆——97%开发者忽略的3个关键参数 DNS解析超时:被忽略的区域路由策略 ElevenLabs 的 API 在印度…...
告别Keil!用Arduino生态玩转国产GD32芯片的3个实战技巧
用Arduino生态解锁GD32开发的三大高阶玩法 在嵌入式开发领域,Keil和IAR等传统工具链长期占据主导地位,但它们的封闭生态和复杂配置流程正在被更开放的解决方案挑战。GD32作为国产MCU的优秀代表,其与Arduino生态的融合为开发者提供了一条高效率…...
别再傻傻做27次实验了!用SPSSAU三分钟搞定正交试验设计(附保姆级极差分析教程)
正交试验设计实战指南:从理论到SPSSAU高效操作 在科研与工程实践中,我们常常面临多因素多水平实验设计的挑战。传统全面试验方法虽然理论严谨,但当因素和水平数量增加时,实验次数呈指数级增长,导致资源浪费和时间成本飙…...
ElevenLabs语音克隆合规红线速查手册,2024最新GDPR+CCPA+中国《生成式AI服务管理暂行办法》三重适配指南
更多请点击: https://intelliparadigm.com 第一章:ElevenLabs语音克隆合规性认知总览 语音克隆技术正以前所未有的精度重塑人机交互边界,但其法律与伦理风险亦同步升级。ElevenLabs 作为行业领先者,明确将《服务条款》第5.2条与《…...
