当前位置: 首页 > news >正文

数据结构——单链表详解

目录

前言

一.什么是链表

1.概念

​编辑

2.分类

二.单链表的实现(不带头单向不循环链表)

2.1初始化

2.2打印

2.3创建新节点

2.4头插、尾插

2.5头删、尾删

2.6查找

2.7在指定位置之前插入

2.8在指定位置之后插入

2.9删除pos位置

2.10删除pos之后的

2.11销毁链表


前言

通过前面所学的顺序表,我们发现存在着几个问题,顺序表的中间/头部的插入需要挪动数据、扩容存在着性能的消耗、或多或少有空间的浪费,由此我们引入链表这一概念.

一.什么是链表

1.概念

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

2.分类

结构多样,根据是否带头,单向/双向,循环/不循环分为8

其中使用较多的是单链表不带头单向不循环链表)和双向链表(带头双向循环链表),这节讲解单链表的实现

二.单链表的实现(不带头单向不循环链表)

2.1初始化

结构的声明和定义

typedef int SLTDataType;
//该链表由节点组成
typedef struct SListNode
{SLTDataType data;struct SListNode* next;//这里不能写成SLTNode,这时还未重命名
}SLTNode;//typedef struct SListNode SLTNode;

2.2打印

这里有pcur去接收phead,然后依次遍历,当pcur指向NULL时跳出循环,最后再打印NULL

void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

2.3创建新节点

与顺序表的扩容不同,这里需要新节点即开辟,不会造成浪费

如果开辟失败,则会报错

SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//新节点if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}

2.4头插、尾插

头插相较于尾插较容易,这里面传递的是二级指针

//链表的头插、尾插
void SLTPushBack(SLTNode** phead, SLTDataType x);
void SLTPushFront(SLTNode** phead, SLTDataType x);//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//链表为空,新节点为pheadif (*pphead == NULL){*pphead = newnode;return;}//链表不为空,找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//为空,跳出循环,此时ptail就是尾节点ptail->next = newnode;
}//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//newnode *ppheadnewnode->next = *pphead;*pphead = newnode;
}

2.5头删、尾删

//链表的头删、尾删
void SLTPopBack(SLTNode** phead);
void SLTPopFront(SLTNode** phead);//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);//链表不为空//链表只有一个节点,有多个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next)//prev ptail ptail->next{prev = ptail;ptail = ptail->next;}prev->next = NULL;//销毁尾节点free(ptail);ptail = NULL;
}//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);//让第二个节点成为新的头//把旧的头节点释放掉SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}

2.6查找

通过遍历链表,查找是否与x相等,若有则返回pcur;若未找到,则返回NULL

//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x)
{assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

2.7在指定位置之前插入

与头插类似

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);//要加上链表不为空,若是空链表,那么前面将断言assert(*pphead);SLTNode* newnode = SLTBuyNode(x);//pos刚好是头节点if (pos == *pphead){//头插SLTPushFront(pphead,x);return;}//pos不是头节点的情况SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev->newnode->posprev->next = newnode;newnode->next = pos;
}

2.8在指定位置之后插入

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = SLTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;pos->next = newnode;
}

2.9删除pos位置

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);//pos刚好是头节点,没有前驱节点,执行头删if (*pphead == pos){//头删SLTPopFront(pphead);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev pos pos->nextprev->next = pos->next;free(pos);pos = NULL;
}

2.10删除pos之后的

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);//删除链表之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//pos->next不能为空assert(pos->next);//pos pos->next pos->next->nextSLTNode* del = pos->next;free(del);del = NULL;
}

2.11销毁链表

//销毁链表
void SListDesTroy(SLTNode** pphead); //销毁链表
void SListDesTroy(SLTNode** pphead)
{assert(pphead);assert(*pphead);SLTNode* pcur = *pphead;while (pcur){SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

如果上述内容对您有帮助,希望给个三连谢谢 

相关文章:

数据结构——单链表详解

目录 前言 一.什么是链表 1.概念 ​编辑 2.分类 二.单链表的实现(不带头单向不循环链表) 2.1初始化 2.2打印 2.3创建新节点 2.4头插、尾插 2.5头删、尾删 2.6查找 2.7在指定位置之前插入 2.8在指定位置之后插入 2.9删除pos位置 2.10删除pos之后的 2.11销毁链表…...

Unity接入GVoice腾讯实时语音

Unity接入GVoice腾讯实时语音 一、介绍二、注册GVoice创建项目语音服务1.创建项目2.申请语音权限3.项目管理查看SDK初始化的一些参数和基本信息4.GVoice检测 三、SDK下载SDK是分为两种类型:独立版集成板 SDK放入Unity工程中 四、语音代码写法五、GVoice踩坑语音权限…...

【Spring基础】从0开始学习Spring(2)

前言 在上篇文章,我已经讲了Spring中最核心的知识点:IoC(控制反转)以及DI(依赖注入)。这篇文章,我将讲一下关于Spring框架中的其它比较琐碎但是又还是挺重要的知识点,因此&#xff…...

cesium mapboxgl+threebox glb 朝向问题

一、3Dbuilder打开glb 二、cesium在pitch和heading都为0的情况下,不设置模型的朝向 三、mapboxglthreebox在pitch和bearing都为0的情况下,不设置模型的朝向 四、对于地图默认视角,cesium设置pitch-90、heading0的时候和mapboxglthreebox设置p…...

LeetCode 打家劫舍

198. 打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个…...

单片机的50个电路

单片机 电源 声音模块 收音机 485 蓝牙 光耦 can 光敏电阻 单片机 矩阵 单片机电路 时钟 ADC 接口电路 红外发射 显示模块 红外接收 蜂鸣器驱动 流水灯 usb供电 烧录电路 数码管 EEPROM LCD1602电路 数码管 max485 红外开关 译码器 移位寄存器 步进电机控制 复位电路 下载电路 …...

JVM 性能调优- 五种内存溢出(5)

在介绍之前先简单介绍下 直接内存(Direct Memory)和堆内存(Heap Memory): 关系: 直接内存并不是Java虚拟机的一部分,它是通过Java的NIO库中的ByteBuffer来分配和管理的。直接内存通常由操作系统的本地内存(Native Memory)提供支持。堆内存是Java虚拟机的一部分,用于存…...

【SQL高频基础】1141.查询近30天活跃用户数

题目: 表:Activity ------------------------ | Column Name | Type | ------------------------ | user_id | int | | session_id | int | | activity_date | date | | activity_type | enum | ------------------------…...

基于spring cloud alibaba的微服务平台架构规划

平台基础能力规划(继续完善更新…) 一、统一网关服务(独立服务) 二、统一登录鉴权系统管理(独立服务) 1.统一登录 2.统一鉴权 3.身份管理 用户管理 角色管理 业务系统和菜单管理 部门管理 岗位管理 字典管…...

leetcode(滑动窗口)3.无重复字符的最长字串(C++详细题解)DAY2

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示…...

Android13 系统源码适配安装可卸载的三方apk应用

Android13 系统源码适配安装可卸载的三方apk应用 文章目录 Android13 系统源码适配安装可卸载的三方apk应用一、前言二、Android 系统运行后默认安装三方apk实现1、Android 系统默认安装三方apk实现主要思路2、Android 系统默认安装三方apk具体实现(1)准…...

flutter使用qr_code_scanner扫描二维码

qr_code_scanner仓库地址:qr_code_scanner | Flutter Package 需要添加android和ios的相机权限和本地相册权限: android中添加权限: 在android\app\build.gradle中修改:minSdkVersion 20 并且在android/app/src/main/AndroidManifest.xml中…...

黑马Java——集合进阶(List、Set、泛型、树)

一、集合的体系结构 1、单列集合(Collection) 二、Collection集合 1、Collection常见方法 1.1代码实现: import java.util.ArrayList; import java.util.Collection;public class A01_CollectionDemo1 {public static void main(String[] a…...

TS项目实战二:网页计算器

使用ts实现网页计算器工具,实现计算器相关功能,使用tsify进行项目编译,引入Browserify实现web界面中直接使用模块加载服务。   源码下载:点击下载 讲解视频 TS实战项目四:计算器项目创建 TS实战项目五:B…...

MySQL的ACID、死锁、MVCC问题

1 ACID ACID代表原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。一个确保数据安全的事务处理系统,必须满足这些密切相关的标准。 原…...

Docker 可视化工具

1、Portainer 概念介绍 Portainer是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。 Portainer分为开源社区版(CE版)和商用版(BE版/EE版)。 Porta…...

【C++】友元:友元函数与友元类

一、友元 友元&#xff08;friend&#xff09;是C中的一种特殊关系&#xff0c;用于在类之间共享访问权限。通过将一个函数或类声明为另一个类的友元&#xff0c;我们可以允许友元访问声明类的非公有成员。 二、友元函数 问题&#xff1a;现在尝试去重载operator<<&am…...

linux之wsl2安装远程桌面

0. 安装后的效果 1. wsl中打开terminal并安装库 sudo apt-get purge xrdp sudo apt install -y xrdp sudo apt install -y xfce4 sudo apt install -y xfce4-goodies 2.优化显示 sudo sed -i s/max_bpp32/#max_bpp32\nmax_bpp128/g /etc/xrdp/xrdp.ini sudo sed -i s/xserverbp…...

如何以管理员身份删除node_modules文件

今天拉项目&#xff0c;然后需要安装依赖&#xff0c;但是一直报错&#xff0c;如下&#xff1a; 去搜这个问题会让把node_modules文件先删掉 再去安装依赖。我在删除的过程中会说请以管理员身份来删除。 那么windows如何以管理员身份删除node_modules文件呢&#xff1f; wi…...

【Linux】环境基础开发工具的使用之gdb详解(三)

前言&#xff1a;上一篇文章中我们讲解了Linux下的gcc与g的使用&#xff0c;今天我们将进一步的学习gdb与makefile来帮我们更好的理解与使用基础开发工具。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:Linux的深度刨析 &#x1f448; …...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...