链表入门(单链表讲)

news2024/11/20 13:27:41

链表

  • 1.链表
    • 1.1 链表概念及其结构
    • 1.2 链表的分类
  • 2.单链表代码实现
    • 2.1 单链表的定义
    • 2.2 单链表的初始化
    • 2.3 单链表的新增结点
    • 2.4 单链表的打印
    • 2.4 单链表的插入
      • 2.4.1 头插
      • 2.4.2 尾插
      • 2.4.3 任意位置插入
    • 2.5 单链表的删除
      • 2.5.1 头删
      • 2.5.2 尾删
      • 2.5.3 任意位置删除
    • 2.6 单链表的查找及其修改

1.链表

1.1 链表概念及其结构

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

  • 链表结构如图所示:
    请添加图片描述

1.2 链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

  1. 单向或者双向
    >

  2. 带头或者不带头

  3. 循环或者非循环

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

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

2.单链表代码实现

2.1 单链表的定义

我们在了解线性结构最重要的就是明白这个结构是如何定义的,是怎样的一种结构。这里单链表的定义,我们考虑的是我们需要这个结构中包含什么,这里我们需要的是一个数据域和一个指针域数据域用于存储数据,指针域用于链接每个单链表节点。行,我们来rua一下:

typedef int SLTDateType;//typedef 一下,方便我们更改所需存储的类型
typedef struct SListNode
{
	SLTDateType data;//数据域,用于存储数据
	struct SListNode* next;//指针域,用于链接下一个结点
}SLTNode;

2.2 单链表的初始化

单链表一般不直接提供初始化接口,是因为单链表的初始化不需要额外的方法来完成,可以通过其他操作来实现。

一般而言,单链表的初始化可以分为两种方式:

  1. 首先创建一个空链表,然后逐个插入节点,直到构建完整的链表。
SLTNode* plist = NULL;//后续只需要不断插入新的结点就可以
  1. 直接在创建链表的过程中完成节点的插入操作,不需要单独的初始化方法。

因此,为了简化接口设计和操作复杂度,单链表通常不提供单独的初始化接口,而是通过其他操作来实现链表的构建和初始化。

2.3 单链表的新增结点

这里就可以看到我们在为一个指针开辟空间后就立马初始化了,和上述第二种初始化的方法相同。

SLTNode* SLTNewNode(SLTDateType x)
{
	SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
	//开辟一个链表结点大小的空间
	if (node == NULL)//检测是否开辟成功
	{
		perror("malloc fail");
		return NULL;
	}
	node->data = x;
	node->next = NULL;
	return node;
}

2.4 单链表的打印

为了方便测试一般我们会使用链表打印接口来查看检测。

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

2.4 单链表的插入

这里涉及到单链表的一个难点,就是这里需要二级指针,我们需要更改一级指针内的元素数据,所以需要用二级指针来更改。就例如我们要改变一个数据类型的值,需要一级指针一样。

在这里插入图片描述

2.4.1 头插

在链表第一个结点前插入。

void SLTPushFront(SLTNode** ppa, SLTDateType x)
{
	assert(ppa);//&plist(ppa)不可能为空,所以需要检测
	SLTNode* newnode = SLTNewNode(x);
	newnode->next = *ppa;//新节点的next指针指向链表开头(*ppa)
	*ppa = newnode;//更新头指针
}

2.4.2 尾插

在链表最后结点后插入

void SLTPushBack(SLTNode** ppa, SLTDateType x)
{
	assert(ppa);	
	SLTNode* newnode = SLTNewNode(x);

	if (*ppa == NULL) //判断链表是否为空
	{
		*ppa = newnode;
	}
	else
	{
		//找尾操作,这里单链表我们只能使用遍历来实现,当找到一个节点的next指针指向null时,就代表找到尾了。
		SLTNode* tail = *ppa;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

2.4.3 任意位置插入

pos前位置插入,我们知道了尾插,这里就相当于把pos位置当做尾,去找pos位置,然后再用头插的思路完成。

//任意位置插入(pos前插入)
void SLTInsertF(SLTNode** ppa, SLTNode* pos, SLTDateType x)
{
	assert(ppa);
	assert(pos);
	if (pos == *ppa)
	{
		SLTPushFront(ppa, x);
	}
	else 
	{
		SLTNode* tmp = SLTNewNode(x);
		SLTNode* prev = *ppa;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = tmp;
		tmp->next = pos;
	}
}

pos位置后插入:学习了任意位置插入,我们其实可以把头插和尾插的实现过程改成调用任意位置插入接口

void SLTInsertB(SLTNode** ppa, SLTNode* pos, SLTDateType x)
{
	assert(ppa);

	if (pos == NULL)
	{
		SLTPushBack(ppa, x);
	}
	else
	{
		SLTNode* newnode = SLTNewNode(x);
		SLTNode* cur = *ppa;
		while (cur != pos->next)
		{
			cur = cur->next;
		}
		pos->next = newnode;
		newnode->next = cur;
	}
}

2.5 单链表的删除

2.5.1 头删

头删的思路就是把头指针指向下一个结点,然后释放开始的结点。

void SLTPopFront(SLTNode** ppa)
{
	assert(ppa);
	assert(*ppa);
	
	SLTNode* tmp = *ppa;
	*ppa = tmp->next;
	free(tmp);
	tmp = NULL;
}

2.5.2 尾删

尾删道理是相通的,找到尾指针,但也要保留尾指针的前一个指针,因为需要在删除尾指针后,把前一个尾指针的next指向空。

void SLTPopBack(SLTNode** ppa)
{
	assert(ppa);
	assert(*ppa);

	 if ((*ppa)->next == NULL)
	{
		free(*ppa);
		*ppa = NULL;
	}
	else
	{
		SLTNode* prev = *ppa;
		SLTNode* tail = prev->next;
		while (tail->next)
		{
			prev = prev->next;
			tail = tail->next;
		}
		prev->next = tail->next;
		free(tail);
		tail = NULL;
	} 
}

2.5.3 任意位置删除

意思相近与尾删。

void SLTEraser(SLTNode** ppa, SLTNode* pos)
{
	assert(ppa);
	assert(*ppa);
	if ((*ppa)->next == NULL||pos==*ppa) 
	{
		SLTPopFront(ppa);
	}
	else
	{
		SLTNode* prev = *ppa;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

2.6 单链表的查找及其修改

链表查找就是对应data,然后遍历返回比较简单,修改的话就是根据返回访问data进行赋值修改

SLTNode* SLTFind(SLTNode* pa, SLTDateType x)
{
	SLTNode* cur = pa;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

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

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

相关文章

华为网络技术基础笔记

2023-2024 一、9/81.典型拓扑2.分层架构3.流量分析4.网线 二、9/15三、9/19 一、9/8 1.典型拓扑 Topolpgy 拓扑 结构 ①总线型 ②星型 网络 要 有 “ 冗余 ”性。 ③树型 ④环型网络(口字型网络) ⑤全互联(全网状) ⑥部分网…

代码随想录 Day7 字符串1 LeetCode T344反转字符串 T541 反转字符串II 151翻转字符串的单词

本文更详细解析来自于:代码随想录 (programmercarl.com) LeetCode T344 反转字符串 链接:344. 反转字符串 - 力扣(LeetCode) 题目思路 这题的思路很简单,只需要创建两个指针,一个指向首字母,一个指向末字母,两两进行交换即可,这里我们要说的就是交换,可…

一个比 ping 更强大、更牛逼的命令行工具

晚上好,我的网工朋友。 遇到网络故障的时候,你一般会最先使用哪条命令进行排障? 基本上大家第一个想到的都是Ping吧。 但除了Ping,还有Traceroute、Show、Telnet又或是Clear、Debug等等好用命令,你都用过吗&#xf…

MD5 绕过第二式:数组绕过

文章目录 参考环境强类型比较运算符雾来哈希碰撞目标 王小云院士与白宫密码王小云院士两度破译白宫密码白宫密码亮剑十年磨一剑 雾散曲径通幽WarrningPHP 中的数组与 md5()尝试绕过PHP8 下的致命错误 参考 项目描述搜索引擎Bing、GoogleAI 大模型文心一言、通义千问、讯飞星火…

正点原子lwIP学习笔记——Jperf测试网速

1. Jperf与iperf简介 iperf是命令行形式的网络性能测试工具;而Jperf就是在iperf的基础上进行UI开发,搭建了界面的图形化网络性能测试工具。 是用来测试TCP/UDP的带宽、延迟抖动和数据包丢失等功能! iperf -c server -ip -p server-port -i 1…

解决GC毛刺问题——转转搜索推荐服务JDK17升级实践

解决GC毛刺问题——转转搜索推荐服务JDK17升级实践 1 升级背景2 JDK17简介2.1 新语法简介2.2 新GC算法简介 3 升级过程3.1 升级步骤3.2 遇到问题及解决方法 4 升级效果4.1 整体耗时对比4.2 分节点耗时对比4.3 GC停顿时长对比4.4 堆空间占用对比 5 总结 1 升级背景 随着转转业务…

HTTPS协议概述

HTTPS(Hypertext Transfer Protocol over Secure Socket Layer,基于安全套接字层的超文本传输协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,…

C语言入门Day_26 结构体

目录 前言: 1.结构体的定义 2.结构体的使用 3.易错点 4.思维导图 前言: 变量只能表示单一的属性,比如用int去表示一个年龄,用float去表示一个身高或一个体重,一个字符串/字符数组去表示一个性别或一个名字。 …

2023年腾讯云服务器优惠活动整理汇总

腾讯云是腾讯集团倾力打造的云计算品牌,为了吸引更多的用户,腾讯云经常会推出各种各样的优惠活动。本文将为大家整理汇总一些腾讯云服务器的优惠活动,希望能够帮助到需要购买腾讯云服务器的用户。 一、腾讯云服务器优惠券 腾讯云优惠券是腾讯…

创建型设计模式——工厂模式

摘要 本博文主要介绍软件设计模式中工厂模式,其中工厂设计模式的扩展为简单工厂(Simple Factory)、工厂方法(Factory Method)、抽象工厂(Abstract Factory)三种。 一、简单工厂(Simple Factory) 主要分析设计模式 - 简单工厂(Simple Factory),它把实例…

腾讯大牛耗时1个月整理的“JVM学习笔记“深入底层,面面俱到!

为什么要学习JVM? 1、 程序调优2、 排查程序运行问题3、 掌握了程序执行的根本和原理4、 规避写代码时候的一些错误5、 应付面试6、 掌握了其他语言的通用机制 怎么有效的学习JVM? 以上了解了学习JVM的种种好处,但是怎么有效的学习JVM呢&a…

029-从零搭建微服务-消息队列(一)

写在最前 如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 源码地址(后端):mingyue: 🎉 基于 Spring Boot、Spring Cloud & Alibaba 的分布式微服务架构基础服务中心 源…

1992-2021年省市县经过矫正的夜间灯光数据(GNLD、VIIRS)

1992-2021年省市县经过矫正的夜间灯光数据(GNLD、VIIRS) 1、时间:1992-2021年3月,其中1992-2013年为年度数据,2013-2021年3月为月度数据 2、来源:1992-2013年来源于DMSP、2013-2021年3月来自VIIRS 3、范…

spring AOP源码阅读分析

理论知识 AOP是面向切面编程(Aspect Oriented Programming)的意思。定义一些切点(pointcut),然后可以在切点织入一些通知(advice),对切点方法进行代理增强,与核心业务逻辑分离开来,以提高系统的可维护性、可扩展性和重…

网工内推 | 网络工程师,软考证书优先,六险一金,包吃

01 科力信息 招聘岗位:网络工程师 职责描述: 1、负责蚌埠项目的设备安装及调试; 2、对边界网络运行中的监控、故障排除、问题处理。 任职要求: 1、2年及以上网络相关工作经验,有交通管理网络运维经验优先&#xff1b…

【移动端测试工具】Appium自动化测试工具安装与配置

文章目录 一、JAVA环境配置检查是否已安装java jdk 二、android SDK安装1.下载android sdk压缩包2.解压压缩包3.安装SDK Manager4.sdk环境变量配置5.验证sdk是否安装成功 三、node JS安装1.下载node.js安装包2.安装node.js3.环境配置4.测试完成验证5.安装淘宝镜像并检验是否安装…

Android MeasureSpec测量规格

文章目录 Android MeasureSpec测量规格概述MeasureSpec组成常用APIMeasureSpec源码分析getChildMeasureSpec源码分析总结 Android MeasureSpec测量规格 概述 MeasureSpec指View的测量规格,MeasureSpec是View的一个静态内部类。 View的MeasureSpec是根据自身的布局…

SoloX:Android和iOS性能数据的实时采集工具

SoloX:Android和iOS性能数据的实时采集工具 github地址:https://github.com/smart-test-ti/SoloX 最新版本:V2.7.6 一、SoloX简介 SoloX是开源的Android/iOS性能数据的实时采集工具,目前主要功能特点: 无需ROOT/越狱…

Java调用操作系统命令的输出乱码问题解决

本篇解决的问题 使用Java 的Runtime调用操作系统的命令,出现异常时使用getErrorStream()获取错误信息的字节流,转换该字节流为字符串显示时,出现乱码。 Java调用操作系统命令 这里以Windows 操作系统为例, 调用cd 命令切换路径…

SAP 销售订单审批状态参数设置

定义权限码 BS52 Spro->控制->内部订单->订单主数据->状态管理->定义状态管理授权码 创建状态参数文件 BS02 SPRO->销售与分销->销售->销售凭证->定义并分配状态参数文件->定义状态参数文件 1)命名,描述 设置对象类型:销…