刨析数据结构(二)

🌈个人主页:小田爱学编程
🔥 系列专栏:数据结构————"带你无脑刨析"
🏆🏆关注博主,随时获取更多关于数据结构的优质内容!🏆🏆


😀欢迎来到小田代码世界~
😁 喜欢的小伙伴记得一键三连哦 ૮(˶ᵔ ᵕ ᵔ˶)ა


一.线性表的链式储存

链表:线性表的链式储存方式,逻辑结构不一定连续,物理结构不一定连续

描述:由数据域和指针域组成

🌏头结点:点是为了操作方便而设立的,放在第一个元素结点之前,不保存任何有意义的数据

🌏头节点:即为指向第一个节点的地址 

🔥链表分类:八种

👨‍🚀 以单链表(不带头单向不循环链表)

 二.单链表

1.优缺点

🔥任意位置插入删除,时间复杂度小
🔥没有增容问题,插入一个开辟一个空间

🔥不支持随机访问

2.创建

//定义链表
typedef int SLTDataType;//数值域
//链表是由节点组成
typedef struct SListNode
{SLTDataType data;//int datastruct  SListNode* next;//它用来存储当前节点的下一个节点的地址
}SLTNode;//typedef struct SListNode SLTNode;

3.打印

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

 

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;
}

4.增加元素

尾插:

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;
}

在指定位置插入

//在指定位置之前插入数据
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;
}

5.删除元素

 尾删

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 = 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;
}

🔥指定位置删除:注意删除的逻辑

//删除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;
}
void SLTEraseAfter(SLTNode* pos) {assert(pos);//pos->next不能为空assert(pos->next);//pos  pos->next  pos->next->nextSLTNode* del = pos->next;pos->next = pos->next->next;free(del);del = NULL;
}

6.修改元素

//给一个数据,找到这个数据所在的节点,并用新数据修改
void SListChangeDate(SLTNode*pphead, SLTDataType x, SLTDataType y)
//不需要改变节点的地址,所以值传递即可 
//x是查找的数据,y是新的数据,用来修改查找的数据                                              
{SLTNode*cru = pphead;while (cru != NULL)//如果没有节点,根本不会进入循环去找{if (cru->data == x){cru->data = y;break;//修改完数据后,就跳出循环}else{cru = cru->next;}}if (cru == NULL)//如果循环完单链表,没有找到要修改的那个数据{printf("要修改的数据不存在,请重新修改数据\n");}else{printf("修改成功\n");}
}

7.查找元素

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

8.销毁链表

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.创建

typedef int LTDataType;
typedef struct ListNode {LTDataType data;struct ListNode* prev;struct ListNode* next;
}LTNode;

3.打印

LTNode* LTInit() {LTNode* phead = LTBuyNode(-1);return phead;
}

4.增加元素

尾插(不需要找尾操作

//尾插
void LTPushBack(LTNode* phead, LTDataType x) {assert(phead);LTNode* newnode = LTBuyNode(x);//phead phead->prev(ptail)  newnodenewnode->next = phead;newnode->prev = phead->prev;phead->prev->next = newnode;phead->prev = newnode;
}

 头插

//头插
void LTPushFront(LTNode* phead, LTDataType x) {assert(phead);LTNode* newnode = LTBuyNode(x);//phead newnode phead->nextnewnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

任意位置插入

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x) {assert(pos);LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}
//删除pos位置的数据
void LTErase(LTNode* pos) {assert(pos);//pos->prev pos  pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

5.删除元素

头删

void LTPopFront(LTNode* phead) {assert(phead);assert(phead->next != phead);LTNode* del = phead->next;LTNode* next = del->next;//phead del nextnext->prev = phead;phead->next = next;free(del);del = NULL;
}

 尾删

void LTPopBack(LTNode* phead) {assert(phead);//链表为空:只有一个哨兵位节点assert(phead->next != phead);LTNode* del = phead->prev;LTNode* prev = del->prev;prev->next = phead;phead->prev = prev;free(del);del = NULL;
}

 任意位置删除

void LTErase(LTNode* pos) {assert(pos);//pos->prev pos  pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

6.修改元素

void DeleteNode(LTNode** pHead, LTNode* toBeDeleted) {if (pHead == NULL || toBeDeleted == NULL) {return;}LTNode* head = *pHead;// 要删除的节点是头节点if (head == toBeDeleted) {*pHead = toBeDeleted->next;}// 调整前驱节点的next指针if (toBeDeleted->prev != NULL) {toBeDeleted->prev->next = toBeDeleted->next;}// 调整后继节点的prev指针if (toBeDeleted->next != NULL) {toBeDeleted->next->prev = toBeDeleted->prev;}free(toBeDeleted);
}

7.查找元素

LTNode* LTFind(LTNode* phead, LTDataType x) {assert(phead);LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x) {return pcur;}pcur = pcur->next;}return NULL;
}

8.销毁链表

void LTDesTroy(LTNode* phead) {//哨兵位不能为空assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//链表中只有一个哨兵位free(phead);phead = NULL;
}

🥇这是博主年前的最后一篇文章哦,年后再继续更新,年后会开启新的刷题专栏!😊

🥇还有不到不到一周就过年喽!祝大家新的一年财源滚滚,学习进步,身体健康,咱们明年见! 

 🎁🎁🎁今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是我前进的动力!

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

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

相关文章

strlen函数详解

🎈个人主页:甜美的江 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:c语言 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步&a…

动态微信小程序码和开发者工具解析小程序码

一、动态生成微信小程序码 1、方式一 微信官方网站,对已发布的小程序,提供了一个快捷的入口,输入微信小程序的page页面即可。 page页面可以通过右侧开启入口获取 也可以通过开发者工具左下角的页面地址和参数地址那里获取到 二、生成的小…

【软件设计师笔记】计算机系统基础知识考点

【考证须知】IT行业高含金量的证书(传送门) 💖 【软件设计师笔记】程序语言设计考点(传送门) 💖 【软件设计师笔记】操作系统考点(传送门) 💖 🐓 计算机系统组成 计算机系统是由硬件和软件组成的,它们协同工作来运…

WAF 无法防护的八种风险

一、目录遍历漏洞 测试用例:Apache 目录遍历漏洞 测试环境搭建: apt intsall apache2 && cd /var/www/html/ && rm index.html无法拦截原因: 请求中无明显恶意特征,无法判断为攻击行为 实战数据: 截…

MongoDB聚合操作

文章目录 聚合操作单一作用聚合聚合管道什么是 MongoDB 聚合框架管道(Pipeline)和阶段(Stage)常用的管道聚合阶段聚合表达式数据准备$project$match$count$group accumulator操作符$unwind$limit$skip$sort$lookup案例聚合操作案例…

【机器学习】AAAI 会议论文聚类分析

实验五:AAAI 会议论文聚类分析 ​ 本次实验以AAAI 2014会议论文数据为基础,要求实现或调用无监督聚类算法,了解聚类方法。 1 任务介绍 ​ 每年国际上召开的大大小小学术会议不计其数,发表了非常多的论文。在计算机领域的一些大…

K8s 集群可观测性-数据分流最佳实践

简介 在微服务架构下,一个 k8s 集群中经常会部署多套业务,同时也意味着不同团队、不同角色、不同的业务会在同一集群中,需要将不同业务的数据在不同的空间进行管理和查看。 在传统的主机环境下,这个是可以通过不同的主机部署 Da…

《元梦之星》赛季更新带来“新”内容,为何却被玩家集体声讨?

前段时间,《元梦之星》迎来了“山海奇遇”赛季的重磅更新,诸多“新”内容的上线吸引了很多玩家们的关注,然而在新版本开启之后没有多,新玩法新时装甚至是游戏中的新改动都引起了不少玩家的不满。 在新赛季开启之后,玩家…

Python爬虫http基本原理

HTTP 基本原理 在本节中,我们会详细了解 HTTP 的基本原理,了解在浏览器中敲入 URL 到获取网页内容之间发生了什么。了解了这些内容,有助于我们进一步了解爬虫的基本原理。 2.1.1 URI 和 URL 这里我们先了解一下 URI 和 URL,URI…

抖音弹幕直播玩法汉字找不同文字找不同无人值执守自动玩游戏自带语音播报的开发日志

#找不同# 要解决如下几个问题: 1.声音sprite的录制和调用,解决方案以及解决库如下: howler.min.js://一款不错的音频播放js库。 2.鼠标自动飘浮,使用的库 anime.min.js 3.资源预加载 preload.min.js 4.其它使用到的库 jquery,vue

stack和queue及优先级队列和适配器(包括deque)的介绍

stack stack的介绍 stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组…

Android使用ScrollView导致鼠标点击事件无效

平台 测试平台: RK3288 Android8.1RK3588 Android 12 问题 首先, 这个问题的前提是, 使用的输入设备是**鼠标**, 普通的触摸屏并不会出现这个问题. 大致的流程是APP的UI布局中采用ScrollView作为根容器, 之后添加各类子控件, 在一起准备就绪后, 使用鼠标进行功能测试, 出现…

国产隔离芯片的质量控制与发展趋势

随着电子技术的飞速发展,国产隔离芯片在电力电子、通信设备等领域中扮演着重要角色。然而,随之而来的是对于其质量控制的迫切需求。本文将从结构、制造工艺、测试手段等方面对国产隔离芯片的质量控制进行分析,并展望其未来的发展趋势。 一、国…

element-ui link 组件源码分享

link 组件的 api 涉及的内容不是很多,源码部分的内容也相对较简单,下面从以下这三个方面来讲解: 一、组件结构 1.1 组件结构如下图: 二、组件属性 2.1 组件主要有 type、underline、disabled、href、icon 这些属性,…

KVM-安装-使用-迁移

一. KVM安装 1. 基础安装 # 下载源 curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo# 安装基础软件 yum -y install tree vim wget bash-completion bash-completion-extras lrzsz net-tools sysstat iotop iftop htop unzip nc nmap …

批量修改文件后缀名

需要将/opt/module/test/路径下的txt文件后缀修改为cpp,并且以年份结尾 代码如下: #!/bin/bashyear2020 directory"/opt/module/test/"cd "$directory" || exit 1for name in *.txt; donew_name"${name%.txt}_${year}.cpp&qu…

SpringBoot security 安全认证(一)——登录验证

本节内容:使用springboot自动security模块实现用户登录验证功能; 登录过程如下图: AuthenticationManager内容实现用户账号密码验证,还可以对用户状态(启用/禁用),逻辑删除,账号是否…

LeetCode.189. 轮转数组

题目 题目链接 分析 首先能想到的就是可以用一个新数组,先保存原数组的后 k 个元素,再保存原数组的前 n−k 个元素。但题目要求不使用额外的数组空间,那么就需要在原数组上做操作。 我们可以先把整个数组翻转一下,这样后半段元…

虚幻UE5Matehuman定制自己的虚拟人,从相机拍照到UE5制作全流程

开启自己的元宇宙,照片扫描真实的人类,生成虚拟形象,保姆级教程,欢迎大家指正。 需要的软件: 制作流程: 一.拍照。 围绕自己拍照,大概20多张图就差不多了,把脑门漏出来,无需拍后脑勺。 拍照方式 例如,拍照时尽量不要在脸上体现出明显的光源方向。

07. 【Linux教程】远程登录

Linux 远程登录 前面介绍了如何安装 Linux 终端工具,本小节介绍本地电脑如何使用 ssh 命令远程登录、Linux 终端工具远程登录的方式,这两种登录方式都是基于 ssh 网络安全协议的,学会使用远程登录 Linux 服务器,会让你对 Linux 系…