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

【数据结构】单链表的实现

本篇主要总结单链表是如何实现的,数据结构是如何管理数据的,详细的介绍每一步是如何实现以及各种注意事项。

  • 🚀1.单链表的实现🚀
      • 🍭1.1单链表的尾插
      • 🍭1.2单链表的头插
      • 🍭1.3单链表的打印
      • 🍭1.4单链表的尾删
      • 🍭1.5单链表的头删
      • 🍭1.6单链表的查找
      • 🍭1.7单链表的插入
      • 🍭1.8单链表的删除

🚀1.单链表的实现🚀

单链表能实现什么功能呢?数据结构对数据的管理无外乎增删查改,让我们一一实现它吧!

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLTData;//在单链表要使用的数据类型,可根据需要改动
typedef struct SLTNode  重定义单链表类型名
{SLTData data;//单链表中结点一般都含有两个元素,一个数据struct SLTNode* next;//一个指向该该结点类型的指针
}SLTNode;//结点
SLTNode* BuySLTNode(SLTData x);//生成新结点的函数
void SLTPrint(SLTNode* pphead);//单链表的打印
void SLTPushBack(SLTNode** pphead,SLTData x);//单链表的尾插
void SLTPushFront(SLTNode** pphead, SLTData x);//单链表的头插
void SLTPopBack(SLTNode** pphead);//单链表的尾删
void SLTPopFront(SLTNode** pphead);//单链表的头删
SLTNode* SLTFind(SLTNode** pphead, SLTData x);//单链表的查找
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTData x);//在pos位置前面插入
void SLTErase(SLTNode** pphead, SLTNode* pos);//在pos位置之前删除
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTData x);//在pos位置之后插入
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos);//在pos位置之后删除

🍭1.1单链表的尾插

单链表的尾插。我们要注意到我们传给尾插函数的是二级指针,也就是指向链表的指针的指针,为什么要传二级指针呢?
因为我们要在该函数内部修改指向链表的指针,让它指向别的的地方去,这就将它修改了,要想将该变量真正的修改成功,从内到外都要修改我们就得传它的指针,不然在函数内部修改成功,但在函数外部没有修改那又有什么用呢?
其实这就是典型的形参的改变不影响实参,只不过如果这里的实参是指向结点的指针,然后尾插函数接收参数也是指向结点的指针,那修改形参就无法改变实参,必须将指向结点的指针的地址传过去,然后用二级指针来接收,这样对形参的修改才可以改变实参。
并且一开始我们还要进行对该二级指针断言,防止有人传错指针,又传入一级指针类型。

好,让我们回到这个尾插函数。
尾插一个结点,我们首先要需要生成一个新的结点newnode.
我们首先想前面有一系列结点,而尾插只要在最后一个结点的后面接上即可,这时我们需要是最后一个结点的地址。
所以我们需要找尾。注意找尾while里进行的条件是tail->next!=NULL,这样才能找到最后一个结点
而不能写成while(tail!=NULL),这样找到的不是最后一个结点而是最后一个结点的后面。

接着我们再分析如果前面没有结点,那么直接将新生成的结点与指向链表的指针链接起来即可。

void SLTPushBack(SLTNode** pphead, SLTData x)//尾插
{assert(pphead);SLTNode* newNode = BuySLTNode(x);//生成一个新结点//如果前面没有结点if (*pphead == NULL){*pphead = newNode;//直接将新结点赋给指向链表的指针}else{//假设前面有结点//找尾SLTNode* tail = *pphead;while(tail->next!= NULL){tail = tail->next;//往后走}tail->next = newNode;//最后将新结点与最后一个结点链接}
}

🍭1.2单链表的头插

单链表的头插。
首先对二级指针断言,看是否合法
先假设前面有结点,然后生成新结点进行头插。
头插就是将指向链表的指针一开始指向新结点,再让原先第一个结点与新结点链接起来。
然后再假设前面没有结点,分析没有结点和有结点都可以。

void SLTPushFront(SLTNode** pphead, SLTData x)//头插
{assert(pphead);//断言判断SLTNode* newNode = BuySLTNode(x);//生成新结点//假设前面有结点.发现有结点和没有结点一样newNode->next = *pphead;//将原先第一个结点与新结点链接起来*pphead = newNode;//再让新结点与指向链表的指针连接起来
}

🍭1.3单链表的打印

单链表的打印。
其实本质也是循环打印,只不过不同与顺序表的下标循环,链表是没有顺序的,根据结点的next来进行循环
我们一般不让形参改动,而是重新将形参赋给给一个新元素,这样使用起来更好,因为如果在使用的过程中,又需要头地址的地方,就可以直接使用。
利用cur进行遍历。注意这里循环的条件是cur!=NULL
而不能写成cur->next!=NULL,如果写成这样那么最后一个元素就无法打印出来了,因为最后一个结点的next就为NULL
到最后一个结点就结束了

void SLTPrint(SLTNode* phead)//打印单链表
{SLTNode* cur = phead;while (cur != NULL){printf("%d->", cur->data);//打印每个结点的数据cur = cur->next;}printf("NULL\n");}

🍭1.4单链表的尾删

单链表的尾删。
我们要想删除数据就要进行判断是否删除过头,每次删除之前都要进行断言判断,一旦删除过头就立刻停止。
所以这里我们除了对二级指针断言之外,还需要对指向链表的指针进行断言也就是一级指针,对二级指针解引用即可。

首先我们假设前面有结点,然后尾删也就是删除最后一个结点,同时还需要将前一个结点的next置NULL
不然就变成野指针了。
这里有两种方法来找到前面一个结点的next。
一种是再定义一个指针prev来记录tail遍历链表的前面结点的位置。
最后tail找到尾结点释放tail,再将prev的next置为NULL,即可。

另一种是通过不去找真正的尾结点而实现。
也就是while(tail->next->next)
这里找的不是真正尾结点,而是尾结点前面的。
最后释放tail->next即可
再将tail->next置为NULL.

接着就是假设前面只要一个结点时,该怎么删呢?直接释放即可。

void SLTPopBack(SLTNode** pphead)//尾删
{assert(pphead);//暴力检查是否删过头assert(*pphead);//假设前面只有一个结点时。if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SLTNode* tail = *pphead;SLTNode* prev = NULL;while (tail->next != NULL){prev = tail;tail = tail->next;}free(tail);prev->next = NULL;}
}

🍭1.5单链表的头删

头删与尾删一样都需要对二级指针和一级指针进行断言判断。
假设前面有结点,进行头删,就是让指向链表的指针指向第二个结点,将第一个结点删除掉。

假设前面没有结点,分析发现都适用。

void SLTPopFront(SLTNode** pphead)//头删
{assert(pphead);assert(*pphead);//暴力检查//假设前面只有一个结点//和//假设前面有结点SLTNode* first = *pphead;*pphead = first->next;//将第二个结点与指向链表的指针链接free(first);//删除第一个结点first = NULL;}

🍭1.6单链表的查找

单链表的查找,就是根据所给的数据进行遍历,没有什么好的方法
如果与给的数据相同则返回该地址。如果找不到就返回NULL。

通常查找与修改连在一起,先查找到该结点的数据,然后对该数据进行修改。

SLTNode* SLTFind(SLTNode** pphead, SLTData x)//查找
{assert(pphead);SLTNode* cur = *pphead;while (cur){if (cur->next == x){return cur;}cur = cur->next;}return NULL;
}

🍭1.7单链表的插入

与上面的讲的单链表的头插和尾插不一样,这里讲的是给定位置pos,然后将数据插入想要插入的位置,不过对于单链表的插入,通常都是在位置pos的前面插入数据,而不是在pos的后面插入数据,我们分别来看看这两种插入的不同

在pos前面插入就想要pos前面结点的地址了,并且遍历循环的条件也发生变化。
插在pos的前面
1.如果链表有结点,那我们将新结点与pos位置前面的结点链接起来,再让pos与新结点链接起来。

如果没有结点就相当于头插了。

2.插在pos的后面

插在后面都不要遍历找了,直接将新结点放在pos的后面,将pos的next与新结点链接,再将新结点与pos链接

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTData x)//在pos位置前面插入
{assert(pphead);assert(pos);//如果没有结点if (pos == *pphead){SLTpushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuySLTNode(x);prev->next = newnode;newnode->next = pos;}
}
void SLTInsertAfter( SLTNode* pos, SLTData x)//在pos位置之后插入
{assert(pos);SLTNode* newnode = BuySLTNode(x);newnode->next = pos->next;pos->next = newnode;
}

🍭1.8单链表的删除

单链表的删除分为在pos位置的前面删除还是在后面删除
不过首先都需要对二级指针和一级指针断言。
1.在pos位置之前删除
假设前面有结点,删除pos前面的结点,需要前面结点位置的地址
找到后将该结点点释放。

假设前面只有一个结点,相当于头删。

2.在pos位置之后删除
首先要将pos后面的结点的位置记录下来
然后将后面的结点与pos链接起来将pos后面的结点释放

void SLTErase(SLTNode** pphead, SLTNode* pos)//在pos位置之前删除
{assert(pphead);assert(pos);if (*pphead == pos){SLTpopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev->next = pos->next;}free(pos);pos = NULL;}
}void SLTEraseAfter( SLTNode* pos)//在pos位置之后删除
{assert(pos);SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}

相关文章:

【数据结构】单链表的实现

本篇主要总结单链表是如何实现的&#xff0c;数据结构是如何管理数据的&#xff0c;详细的介绍每一步是如何实现以及各种注意事项。&#x1f680;1.单链表的实现&#x1f680;&#x1f36d;1.1单链表的尾插&#x1f36d;1.2单链表的头插&#x1f36d;1.3单链表的打印&#x1f3…...

从0到1做产品!产品设计的6个步骤

相信不少产品经理在刚入行时&#xff0c;都遇到过这样的情况&#xff1a; 接到需求后不知所措&#xff0c;然后下意识地照着竞品开始盲目地画原型。 其实&#xff0c;这样的设计过程不仅缺乏逻辑性&#xff0c;在后续阶段也很容易出现各种问题。 在此&#xff0c;跟大家分享一下…...

ESP32遥控器软硬件设计

一. 前言 做智能车 或者 四轴飞控怎么能少得了遥控器呢&#xff01;在这里给大家分享一个简单的基于ESP32遥控器的设计&#xff0c;包括软硬件以及3D外壳。 二. 硬件设计 1. 功能介绍 遥控器嘛&#xff0c;通信方式是最重要的&#xff0c;本设计支持 WIFI、蓝牙 和 2.4G&…...

vue-template-admin的keep-alive缓存与移除缓存

一&#xff0c;场景 A页面是表单页面&#xff0c;填写后需要跳转B页面。如果B页面不操作返回的话&#xff0c;应该能还原A页面的内容&#xff0c;而如果B页面点击提交&#xff0c;再回到A页面的时候&#xff0c;应该清除缓存。 二&#xff0c;实现方法 A页面要缓存数据&…...

【人工智能 AI】机器学习快速入门教程(Google)

目录 机器学习术语 标签 特性 示例 模型 回归与分类 深入了解机器学习&#xff1a;线性回归 深入了解机器学习&#xff1a;训练和损失 平方损失函数&#xff1a;一种常用的损失函数 机器学习术语 预计用时&#xff1a;8 分钟 什么是&#xff08;监督式&#xff…...

适配器模式

概览 适配器模式是一种结构型设计模式&#xff0c;用于将一个类的接口转换为客户端所期望的另一种接口。通常情况下&#xff0c;这种转换是由一个适配器类完成的&#xff0c;适配器类包装了原始类&#xff0c;并实现了客户端所期望的接口。这种模式非常适用于在不修改现有代码…...

00后跨专业学软件测试,斩获8.5K高薪逆袭职场

我想说的第一句&#xff1a;既然有梦想&#xff0c;就应该去拼搏还记得&#xff0c;我大学毕业前&#xff0c;就已经暗下决心到xxx培训机构接受培训。那个时候&#xff0c;没有任何海同公司的人主动找我或者联系过我&#xff0c;我是自己在网上发现了xxxx培训机构的&#xff01…...

数据结构和算法学习

文章目录精通一个领域切题四件套算法算法的五个条件流程图数据结构数据与信息数据信息数据结构和算法数据结构算法时间复杂度空间复杂度数组 Array优点缺点数组和链表的区别时间复杂度链表 Linked List优点缺点时间复杂度单向链表双向链表循环链表双向循环链表堆栈 Stack队列 Q…...

剑指 Offer II 012. 左右两边子数组的和相等

题目链接 剑指 Offer II 012. 左右两边子数组的和相等 easy 题目描述 给你一个整数数组 nums&#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那…...

Java货物摆放

题目描述 小蓝有一个超大的仓库&#xff0c;可以摆放很多货物。 现在&#xff0c;小蓝有 &#xfffd; n 箱货物要摆放在仓库&#xff0c;每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向&#xff0c;每箱货物的边都必须严格平行于长、宽、高。 小蓝希望所…...

计算机求解满足三角形各边数字之和相等的数字填充

圆圈处不重复的填入1至9&#xff0c;使得每条边的四个数字相加的总和相等。 求解思路&#xff1a; 数组中存放1到9的数字&#xff0c;每次随机交换两个数字&#xff0c;构建出新的数字组合&#xff0c;计算这个数字组合是否符合要求。 #include <stdio.h> #include <…...

python魔术方法

魔术方法 魔术方法就是一个类中的方法&#xff0c;和普通方法唯一的不同是普通方法需要调用&#xff0c;而魔术方法是在特定时刻自动触发。这些魔术方法的名字特定&#xff0c;不能更改&#xff0c;但是入口参数的名字可以自己命名。 基本魔术方法 new(cls[,…]) _new_ 是在…...

从0开始学python -48

Python CGI编程-3 CGI中使用Cookie 在 http 协议一个很大的缺点就是不对用户身份的进行判断&#xff0c;这样给编程人员带来很大的不便&#xff0c; 而 cookie 功能的出现弥补了这个不足。 cookie 就是在客户访问脚本的同时&#xff0c;通过客户的浏览器&#xff0c;在客户硬…...

当面试官问我前端可以做的性能优化有哪些

面试过程中面试官问到前端性能优化有哪些&#xff0c;当我咔咔一顿输出之后面试官追问&#xff1a;前端可以做的性能优化有哪些呢&#xff1f; 前端优化大概可以有以下几个方向&#xff1a; 网络优化页面渲染优化JS优化图片优化webpack打包优化React优化Vue优化 网络优化 D…...

一文读懂Java/O流的使用方法和技巧

1.前言 Java 中的 I/O 流是实现输入和输出的一种机制&#xff0c;可以用来读写文件、网络、内存等各种资源。Java 提供了各种类型的流&#xff0c;包括字节流和字符流&#xff0c;以及面向文本和二进制数据的流。在本文中&#xff0c;我们将深入探讨 Java I/O 流的各个方面&am…...

AI for Science系列(二):国内首个基于AI框架的CFD工具组件!赛桨v1.0 Beta API介绍以及典型案例分享!

AI for Science被广泛认为是下一代科研范式&#xff0c;可以有效处理多维度、多模态、多场景下的模拟和真实数据&#xff0c;解决复杂推演计算问题&#xff0c;加速新科学问题发现[1] 。百度飞桨科学计算工具组件赛桨PaddleScience是国内首个公开且可应用于CFD&#xff08;Comp…...

SpringCloud简单介绍

文章目录1. 开源组件2. CAP原则1. 开源组件 功能springcloud netflixspringcloud alibabaspringcloud官方其他服务注册与发现eurekanacosconsulzookeeper负载均衡ribbondubbo服务调用openFeigndubbo服务容错hystrixsentinel服务网关zuulgateway服务配置的同一管理cofig-server…...

《uniapp基础知识》学习笔记Day38-(Period2)全局文件一些常用的配置

如果进行开发的话&#xff0c;首先要配置路由页面 page.json 页面路由 pages.json 文件用来对 uni-app 进行全局配置&#xff0c;决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。 {"pages": [{"path": "pages/component/index…...

APICloud 弹动与滚轴冲突的解决模拟

当打开页面的bounces开关来实现下拉刷新和上翻加载是&#xff0c;如果页面中有scroll-view&#xff0c;那么手指上下滑动时弹动会触发&#xff0c;而滚轴无法正常实现&#xff0c;只有按住不动再拖动滚轴才会触发。开始想通过获取手指点击屏幕的坐标点设置触发条件来解决两者的…...

Spring Cloud(微服务)学习篇(四)

Spring Cloud(微服务)学习篇(四) 1.nacos实现服务之间传参数 1.1 在dto包(shop-sms-api项目)中创建SmsDTO类 package com.zlz.shop.sms.api.dto;import lombok.Data;Data public class SmsDTO {private String tel; }1.2 复制SmsDTO类到shop-sms-server项目的dto包下面 1.3 …...

【Java Pro】001-Java基础:面向对象

【Java Pro】001-Java基础&#xff1a;面向对象 文章目录【Java Pro】001-Java基础&#xff1a;面向对象一、面向对象1、什么是对象现实生活中的对象与程序中的对象2、什么是面向对象面向过程面向对象3、面向过程与面向对象的比较思想方面设计方式方面实现方式方面4、面向过程与…...

ElasticSearch从0到1——基础知识

1.ES是什么&#xff1f; 是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能&…...

【面试系列】equals和==的区别

问题&#xff1a;两个对象值相同(x.equals(y) true)&#xff0c;但是可能存在hashCode不同吗? 的定义 比较的是两个对象的内存地址&#xff0c;相等则意味着内存地址一样。 对象的equals方法 Object#equals public boolean equals(Object obj) {return (this obj);}Stri…...

存在重复元素模块-三道题

文章目录存在重复元素217. 存在重复元素219. 存在重复元素 II220. 存在重复元素 III &#xff08;SortedList二分&#xff09;小结存在重复元素 217. 存在重复元素 题目链接&#xff1a;217. 存在重复元素 题目大意&#xff1a;给你一个整数数组 nums 。如果任一值在数组中出…...

3种方法删除7-Zip压缩包的密码

7-Zip压缩软件是一款完全免费且开源的软件&#xff0c;不仅能压缩和解压7-Zip压缩包&#xff0c;还能给压缩包设置打开密码。 有些小伙伴可能会遇到这样的问题&#xff0c;7-Zip压缩包设置密码后&#xff0c;过了一段时间不需要密码保护了&#xff0c;或者一不小心忘记了密码&…...

Codeforces Round 855 (Div. 3)(A~F)

A. Is It a Cat?定义满足条件的字符串为&#xff1a;其中仅可能含有meow四种字母的大小写&#xff0c;而且相同种类的字母必须挨在一起&#xff0c;四种字母的顺序必须按照meow排列。给出一个字母串&#xff0c;求是否满足条件。思路&#xff1a;感觉是个很麻烦的模拟。首先把…...

【SpringCloud】SpringCloud详解之Feign实战

目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.使用Feign远程调用(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽…...

tuts4you上lena‘s40个crackme(1)

本来是不打算写文章了&#xff0c;因为懒&#xff0c;想以后通过录屏的形式保存一下自己学的路程。但奈何开学后一直没找到机会&#xff0c;在宿舍也不愿意大吼大叫的讲东西&#xff0c;只好再写写文章了 最近学了一些汇编语言和逆向工程&#xff0c;所以就想通过这40给题目来看…...

研讨会回顾 | Perforce版本控制工具Helix Core入华十年,携手龙智赋能企业大规模研发

2023年2月28日&#xff0c;龙智联合全球领先的数字资产管理工具厂商Perforce共同举办Perforce on Tour网络研讨会&#xff0c;主题为“赋能‘大’研发&#xff0c;助力‘快’交付”。 作为Perforce Helix Core产品在中国地区的唯一授权合作伙伴&#xff0c;龙智董事长何明女士为…...

C++ vscode 开发环境搭建

C vscode 开发环境搭建 笔记内容&#xff1a; C vscode 开发环境搭建准备了解g命令编译调试掌握使用launch.json和tasks.json配置文件编译调试了解使用cmake构建 git: https://github.com/weichangk/hellocpp/tree/master/vscodecmakecpp 环境搭建准备 安装vscode安装qt&a…...

青岛网站seo技巧/seo外链工具有用吗

一、Spring数据访问模板 Spring提供的数据访问模板&#xff0c;分别适用于不同的持久化机制。 模板类&#xff08;org.springframework.*&#xff09;用途jca.cci.core.CciTemplateJCA CCI连接jdbc.core.JdbcTemplateJDBC连接jdbc.core.namedparam.NamedParameterJdbcTemplate支…...

b2c网站的认识/哪里可以代写软文

对于大部分IT人士来说&#xff0c;给电脑重装系统、迁移操作系统、给硬盘分区、磁盘分区克隆等都是经常要做且不得不做的事情&#xff0c;那么使用哪款软件来管理磁盘分区&#xff0c;就成了大多数人比较纠结的问题。究竟有没有什么分区管理软件是比较靠谱又安全的呢&#xff1…...

哪家企业网站建设好/我的百度账号登录

以前一直没有仔细想过为什么如何设置随机数种子&#xff1f;设置随机数种子有什么用&#xff0c;今天有时间&#xff0c;拿出来分析一下&#xff1a; 直接通过rand() 函数获得随机数每次都会是一样&#xff0c;例如&#xff0c;第一次程序运行的时候是8&#xff0c;第二次运行还…...

石湾做网站公司/怎么注册自己的网站域名

一、监视内存计数器要监视内存不足的状况&#xff0c;请从以下的对象计数器开始&#xff1a;1.内存信息&#xff1a;Memory\ Available BytesMemory\ Pages/secMemory\ Available Bytes如果您怀疑有内存泄露&#xff0c;请监视 Memory\Available Bytes 和 Memory\ Committed By…...

双流规划建设管理局网站/爱站网关键词查询网站的工具

一、 数据库的导出(expdp)1.创建默认导出目录SQL>create directory [dirname] as ‘[dirpath]’;2.赋予指定用户在此目录的读写权限SQL>GRANT READ, WRITE ON DIRECTORY [dirname] to [dbuser];3.使用expdp导出数据库① 导出完整schema> expdp [username/passwd]DUMPF…...

北京推广网站/广州市新闻发布

2019独角兽企业重金招聘Python工程师标准>>> 1.停止mysql服务 2.转至mysql安装目录的 bin 目录下 3.运行 mysqld --skip-grant-tables 4.新开cmd窗口&#xff0c;直接输入 mysql 然后不输入密码回车. 5.use mysql; 6.更新密码 update user set passwordpasswor…...