数据结构:单链表

文章目录

  • 1. 单链表的概念及结构
  • 2. 单链表相关操作
    • 2.1 创建节点
    • 2.2 尾插
    • 2.3 打印
    • 2.4 头插
    • 2.5 尾删
    • 2.6 头删
    • 2.7 查找
    • 2.8 指定位置后插入
    • 2.9 指定位置前插入
    • 2.10 删除指定位置
    • 2.11 删除指定位置后的节点
    • 2.12 销毁单链表
  • 3. 链表种类

在这里插入图片描述

1. 单链表的概念及结构

概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
在这里插入图片描述
链表的结构跟火车车厢相似,淡季时车次的车厢会相应减少,旺季时车次的车厢会额外增加几节。只需要将火车里的某节车厢去掉/加上,不会影响其他车厢,每节车厢都是独立存在的。

与顺序表不同的是,链表里的每节"车厢"都是独立申请下来的空间,我们称之为“结点/节点”。节点的组成主要有两个部分:当前节点要保存的数据和保存下⼀个节点的地址(指针变量)

为什么还需要指针变量来保存下⼀个节点的位置?
链表中每个节点都是独立申请的(即需要插入数据时才去申请⼀块节点的空间),我们需要通过指针变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。

因此链表的结构我们可以这样设计:

typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;       //节点数据struct SListNode* next; //指针保存下⼀个节点的地址
}SLTNode;

注意:

  • 链式结构在逻辑上是连续的,在物理结构上不⼀定连续
  • 节点⼀般是从堆上申请的
  • 从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

2. 单链表相关操作

2.1 创建节点

//创建节点
SNode* BuyNode(SLDatatype x)
{SNode* newnode = (SNode*)malloc(sizeof(SNode));if (!newnode){perror("malloc");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}

2.2 尾插

  • 若当前链表尾空,则插入节点就是头节点
  • 不为空,先找尾,再插入
//尾插
void SListPushBack(SNode** pphead, SLDatatype x)
{assert(pphead);SNode* newnode = BuyNode(x);//链表为空if (*pphead == NULL){*pphead = newnode;return;}SNode* tail = *pphead;//找尾while (tail->next){tail = tail->next;}//连接tail->next = newnode;
}

2.3 打印

//打印
void SListPrint(SNode* phead)
{SNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}

在这里插入图片描述

2.4 头插

  • 先将新节点指向头节点
  • 新节点变为新的头节点
//头插
void SlistPushFront(SNode** pphead, SLDatatype x)
{assert(pphead);SNode* newnode = BuyNode(x);newnode->next = *pphead;*pphead = newnode;
}

2.5 尾删

  • 链表不能为空
  • 找尾节点,同时记录其前驱节点
    • 若只有头节点,则将头节点置空
    • 多个节点,释放尾节点,将其前驱节点的next置空
void SlistPopBack(SNode** pphead)
{assert(pphead);//链表不为空assert(*pphead);//只有一个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}//多个节点SNode* cur = *pphead;SNode* prev = NULL;while(cur->next){prev = cur;cur = cur->next;}//释放尾节点free(cur);cur = NULL;prev->next = NULL;
}

在这里插入图片描述

2.6 头删

  • cur记录当前头节点,头节点后移
  • 释放cur
void SlistPopFront(SNode** pphead)
{assert(pphead);assert(*pphead);SNode* cur = *pphead;*pphead = (*pphead)->next;free(cur);cur = NULL;
}

在这里插入图片描述

2.7 查找

找到目标,返回指向该目标的指针

//查找
SNode* SListFind(SNode** pphead, SLDatatype x)
{assert(pphead);SNode* cur = *pphead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

2.8 指定位置后插入

  • 将新节点与pos的后继节点连接
  • pos节点指向新节点
//指定位置后插入
void SListInsertAfter(SNode* pos, SLDatatype x)
{assert(pos);SNode* newnode = BuyNode(x);newnode->next = pos->next;pos->next = newnode;
}

2.9 指定位置前插入

  • 若指定位置为头节点,则选择头插
  • 找到pos位置的前驱节点,与新节点相连
void SListInsertBefore(SNode** pphead, SNode* pos, SLDatatype x)
{assert(pphead);assert(pos);//指定位置为头节点,执行头插if (pos == *pphead){SlistPushFront(pphead, x);return;}//找pos位置的前驱SNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}SNode* newnode = BuyNode(x);cur->next = newnode;newnode->next = pos;
}

在这里插入图片描述

2.10 删除指定位置

  • 若指定位置为头节点,执行头删
  • 前驱节点指向后继节点,释放当前节点
void SListDelePos(SNode** pphead, SNode* pos)
{assert(pphead);assert(pos);//指定位置为头节点,执行头删if (pos == *pphead){SlistPopFront(pphead);return;}SNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}cur->next = pos->next;free(pos);pos = NULL;
}

在这里插入图片描述

2.11 删除指定位置后的节点

  • 指定位置后必须有节点
  • 记录指定位置后的节点
  • pos指向指定位置后的后继节点
  • 释放指定位置后的节点
void SListDeleAfter(SNode* pos)
{assert(pos);//后面得有元素assert(pos->next);SNode* dele = pos->next;pos->next = dele->next;free(dele);dele = NULL;
}

2.12 销毁单链表

  • 先记录后继节点,再销毁当前节点
void SListDestroy(SNode** pphead)
{assert(pphead);assert(*pphead);SNode* next = NULL;while (*pphead){next = (*pphead)->next;free(*pphead);*pphead = next;}
}

3. 链表种类

链表的结构非常多样,以下情况组合起来就有8种(2x2x2)链表结构:
在这里插入图片描述

在这里插入图片描述
虽然有这么多的链表的结构,但是我们实际中最常用还是两种结构: 单链表双向带头循环链表

  1. 无头单向非循环链表:结构简单,⼀般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。
  2. 带头双向循环链表:结构最复杂,⼀般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

wespeaker项目grpc-java客户端开发

非常重要的原始参考资料: 链接: triton-inference-server/client github/grpc java ps: 使用grpc协议的其它项目python/go可以参考git hub目录client/tree/main/src/grpc_generated下的其它项目 其它链接: 想要系统了解triton-inference-ser…

R语言:箱线图绘制(添加平均值趋势线)

箱线图绘制 1. 写在前面2.箱线图绘制2.1 相关R包导入2.2 数据导入及格式转换2.3 ggplot绘图 1. 写在前面 今天有时间把之前使用过的一些代码和大家分享,其中箱线图绘制我认为是非常有用的一个部分。之前我是比较喜欢使用origin进行绘图,但是绘制的图不太…

鸿蒙内核框架

1 内核概述 内核简介 用户最常见到并与之交互的操作系统界面,其实只是操作系统最外面的一层。操作系统最重要的任务,包括管理硬件设备,分配系统资源等,我们称之为操作系统内在最重要的核心功能。而实现这些核心功能的操作系统模…

VS编译器对scanf函数不安全报错的解决办法(详细步骤)

📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 🙏小杨水平有…

kubesphere部署k8s-v1.23.10

功能: 🕸 部署 Kubernetes 集群 🔗 Kubernetes 多集群管理 🤖 Kubernetes DevOps 🔎 云原生可观测性 🧩 基于 Istio 的微服务治理 💻 应用商店 💡 Kubernetes 边缘节点管理 &#x1…

数据分析基础之《pandas(4)—pandas画图》

1、DataFrame.plot(xNone, yNone, kindline) 说明: x:设置x轴标签 y:设置y轴标签 kind: line 折线图 bar 柱状图 hist 直方图 pie 饼图 scatter 散点图 # 找到p_change和turnover之间的关系 data.plot(xvolume, yturnover, kinds…

AUTOSAR CP--chapter2Autosar简介

Autosar简介 安全:使用严格的标准化去约束; 高效:通过提高软件模块的可移植性和复用性来提升; 灵活:通过上位机剪裁配置,自动生辰的手段来实现。 Autosar标准从行业高度统一了各个角色间的分工、接口以及方…

Flink 1.18.1的基本使用

系统示例应用 /usr/local/flink-1.18.1/bin/flink run /usr/local/flies/streaming/SocketWindowWordCount.jar --port 9010nc -l 9010 asd asd sdfsf sdf sdfsdagd sdf单次统计示例工程 cd C:\Dev\IdeaProjectsmvn archetype:generate -DarchetypeGroupIdorg.apache.flink -…

计算机服务器中了locked勒索病毒怎么处理,locked勒索病毒解密数据恢复

网络技术的不断发展,为企业的生产生活提供了极大便利,但也为网络安全带来严重威胁。近期,云天数据恢复中心接到某集团企业的求助,企业的计算机服务器遭到了locked勒索病毒攻击,导致企业系统内部的金蝶账套全部被加密&a…

正则表达式补充以及sed

正则表达式: 下划线算 在单词里面 解释一下过程: 在第二行hello world当中,hello中的h 与后面第一个h相匹配,所以hello中的ello可以和abcde匹配 在world中,w先匹配h匹配不上,则在看0,r&#…

英码科技携手昇腾共建算力底座:推出EA500I超强AI处理能力边缘计算盒子!

在数字经济浪潮中,算力已成为不可或缺的驱动力,为各行各业的数字化转型提供了强大的推动力。面对多元化和供需不平衡的挑战,需要实现从理论架构到软硬件实现的质的飞跃,以满足持续增长的算力需求,华为昇腾在这一方面展…

游戏后端如何实现服务器之间的负载均衡?

在当今的游戏行业中,随着游戏用户数量的不断增加,如何实现服务器之间的负载均衡成为了一个亟待解决的问题。游戏后端作为游戏的重要组成部分,承载着游戏逻辑处理和数据存储等功能,因此游戏后端的负载均衡问题尤为重要。本文将详细…

如何实现算力智能选择

为什么需要对算力进行智能选择 随着科技的飞速发展,算力已经成为制约人工智能应用性能的关键因素。为了满足各种应用场景下的计算需求,算力网络应运而生,它通过对分散的计算资源进行整合,并灵活地分配和调度,逐步推动算…

虚拟飞控计算机:飞行控制系统验证与优化的利器

01.背景介绍 随着航空技术的飞速发展,飞行控制系统作为飞机的心脏,全面负责监测、调整和维持飞行器的姿态、航向、高度等参数,用以确保飞行的安全和稳定。为了满足这些要求,现代飞控系统通常采用先进的处理器和外设来确保其高效、…

智能运维哪些算法?智能运维包含哪些

在智能运维领域,详细介绍一些关键的算法,并阐述这些算法是如何被应用于智能运维系统中的。此外,关于智能运维中包含的主要组成部分或功能模块,以及它们各自的作用和重要性。如何应用再场景中应用在智能运维行业,一些关…

从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器

导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客 上一章我们完成了netty服务启动的相关抽象(https://blog.csdn.net/money9sun/article/details/136025471),这一章我们再新增一个全…

2023 OpenHarmony 年度运营报告

汇聚 70 家企业 6700名贡献者力量, OpenHarmony 已成为下一代智能终端操作系统根社区; 我们在成长,OpenHarmony 项目群成员单位增至 35 家; 2023 年持续迭代更新 6 个版本及 OpenHarmony4.0 重点特性简介……

09_树莓派_树莓派外设板_GPIO_按键的中断与消抖

目录 1.树莓派外设集成板总体介绍 2.第一部分 按键矩阵 GPIO_按键与中断 3.实现效果 1.树莓派外设集成板总体介绍 1)前言:这是一块为了验证树莓派【兼容树莓派多个型号】的40pins的外设接口的外接板,告别复杂的面包板外设搭建。【欢迎各位…

EMNLP 2023精选:Text-to-SQL任务的前沿进展(上篇)——正会论文解读

导语 本文记录了今年的自然语言处理国际顶级会议EMNLP 2023中接收的所有与Text-to-SQL相关(通过搜索标题关键词查找得到,可能不全)的论文,共计12篇,包含5篇正会论文和7篇Findings论文,以下是对这些论文的略…

安卓动态链接库文件体积优化探索实践

背景介绍 应用安装包的体积影响着用户下载量、安装时长、用户磁盘占用量等多个方面,据Google Play统计,应用体积每增加6MB,安装的转化率将下降1%。 安装包的体积受诸多方面影响,针对dex、资源文件、so文件都有不同的优化策略&…