链表详讲(附代码)

news2025/1/10 16:14:07

1.什么是链表

链表是一种非常常见的数据结构,在程序设计中经常被使用。它由一系列节点组成,每个节点都有用来存放数据的数据区以及存放下一个节点地址指针的地址区。跟顺序表不同的是,链表的节点之间的空间并非是连续的,依靠地址区的值找到下一个节点的位置,这样相互链接成的链状结构我们称之为链表。

2.链表的优缺点

链表和顺序表其实是互补的好兄弟,换句话来说,顺序表的优点是链表的缺点,而链表的优点又恰恰是顺序表的缺点。

2.1链表的优点

链表的优点在于它的灵活性,相比于数组,链表可以更方便地进行插入和删除操作,这是因为链表的节点可以在内存中任意位置创建和删除,而数组需要通过整体移动来实现插入和删除操作,效率较低。

相比于顺序表,链表一般不会造成空间的浪费,而顺序表则会因为扩容的问题往往开辟出较大的空间,会存在一定的浪费。

2.2链表的缺点

链表的缺点在于查找,它在随机访问和查找元素时效率不如数组,因为每个节点只能通过指针一步一步向下查找。

先比于顺序表,顺序表查找的时间可以达到O(1),而链表通常是O(n).

2.3总结

根据链表的优点,我们可以在频繁插入、删除操作但不需要随机访问和查找元素时使用这种数据结构。

例如,在计算机科学中,许多常见问题,如哈希表、图、堆栈、队列等,都可以使用链表作为基础数据结构来实现。

3.代码模拟链表(c语言)

3.1功能函数的声明:

SList.h头文件:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos);

// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
// 删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos);
//销毁链表
void SLTDestroy(SListNode** pphead);

功能呢,无非就是常见的各种增、删、查、改。

但是值得注意的是,由于我这里链表的节点是结构体,用head结构体指针来指向该链表的头节点,所以在传参的时候要注意一级指针和二级指针的区别。

比如说假如我们要修改head指向的节点,这个时候我们修改的值是一个指针,所以传参进来要用二级指针。

3.2功能函数的实现

SList.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SList.h"

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x) {
	SListNode* res = (SListNode*)malloc(sizeof(SListNode));
	res->data = x;
	res->next = NULL;
	return res;
}

// 单链表打印
void SListPrint(SListNode* plist) {
	while (plist != NULL) {
		printf("%d ->", plist->data);
		plist = plist->next;
	}
	/*printf("%d->", plist->data);
	plist = plist->next;*/

	printf("NULL \n");
}

// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x) {
	assert(pplist);
	SListNode* temp = BuySListNode(x);
	if (*pplist == NULL) {//当前链表没有节点
		*pplist = temp;
	}
	else {
		SListNode* tail = *pplist;
		while (tail->next != NULL) {
			tail = tail->next;
		}
		temp->next = NULL;
		tail->next = temp;

		//*pplist = tail;
	}
	return;

}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x) {
	assert(pplist);
	SListNode* temp = BuySListNode(x);
	if (*pplist == NULL) {//当前链表没有节点
		*pplist = temp;
	}
	else {
		temp->next = *pplist;
		*pplist = temp;
	}
	return;
}
// 单链表的尾删
void SListPopBack(SListNode** pplist) {
	assert(pplist && *pplist);
	SListNode* tail = *pplist;
	if ((*pplist)->next == NULL) {//只有一个节点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* pre = NULL;
		while (tail->next != NULL) {
			pre = tail;
			tail = tail->next;
		}
		free(tail);
		pre->next = NULL;
	}
}
// 单链表头删
void SListPopFront(SListNode** pplist) {
	assert(pplist&&*pplist);
	if ((*pplist)->next==NULL) {//只有一个节点
		free(*pplist);
		*pplist = NULL;
	}
	else {
		SListNode* temp = (*pplist)->next;
		free(*pplist);
		*pplist = temp;
	}
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x) {
	assert(plist);
	while (plist!=NULL) {
		if (plist->data == x) {
			return plist;
		}
		plist = plist->next;
	}
	return NULL;
}
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x) {
	assert(pos);
	SListNode* temp = BuySListNode(x);
	if (pos->next == NULL) {
		pos->next = temp;
		temp->next = NULL;
	}
	else {
		temp->next = pos->next;
		pos->next = temp;
	}
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos) {
	assert(pos&&pos->next);
	SListNode* temp = pos->next->next;
	free(pos->next);
	pos->next = temp;
}
// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x) {
	assert(*pphead && pos);
	SListNode* temp = BuySListNode(x);
	if ((*pphead)->next == NULL||(*pphead)==pos) {
		temp->next = (*pphead);
		*pphead = temp;
	}
	else {
		SListNode* pre = NULL;
		SListNode* cur = *pphead;
		while (cur->next!= NULL) {
			if (cur== pos)break;
			pre = cur;
			cur = cur->next;
		}	
		temp->next = pre->next;
		pre->next = temp;
	}

}
// 删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos) {
	assert(*pphead && pos);
	if ((*pphead) == NULL) {
		free(*pphead);
		*pphead = NULL;
	}
	else {
		SListNode* pre = NULL;
		SListNode* cur = *pphead;
		while (cur->next != NULL) {
			if (cur == pos)break;
			pre = cur;
			cur = cur->next;
		}
		SListNode* temp = cur->next;
		free(cur);
		if (pre == NULL) {
			*pphead = temp;
		}
		else {
			pre ->next= temp;
		}
	}
}
//销毁链表
void SLTDestroy(SListNode** pphead) {
	assert(*pphead);
	SListNode* ph = *pphead;
	while (ph!= NULL) {
		SListNode* temp = ph->next;
		free(ph);
		ph = temp;
	}
	*pphead = NULL;
}

由于是用malloc动态开辟空间,在删除操作的时候我们要使用free及时释放,避免照成空间泄露的问题。

代码经过测试应该是没有太大的问题,基本功能也都能实现。

这里我想强调一点,为什么我们要模拟链表的功能呢?

模拟各种数据结构的功能可以让我们理解得更加透彻,能较为清晰的明白各种数据结构内部代码大概是怎么实现的。我认为,这对数据结构的熟练运用是有非常大的帮助的。

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

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

相关文章

最新waymo数据集 百度网盘

最新waymo数据集介绍 waymo数据集是有史以来最大&#xff0c;最多样化的自动驾驶数据集&#xff0c;包含 传感器数据边界框数据2D视频全景分割标签关键点标签3D语义分割标签2D和3D边界框的关联 是该领域质量最高、规模最大的数据集之一&#xff0c;用于帮助研究界在机器感知…

【Orangepi Zero2 全志H616】开发板资料(刷机、系统烧录)及环境搭建

一、资料文档 二、MobaXterm远程连接工具 三、修改登录密码 四、修改内核日志等级 五、配置网络 六、SSH 访问 OrangePi ZERO 2 七、配置 vim 八、基于官方外设开发SDK 一、资料文档 官网资料下载 GitHub&#xff1a;新版本的 orangepi-build 源码 环境搭建&#xff1a;新手配…

IP协议汇总

IP协议 1.基本概念 IP协议全称为“网际互连协议&#xff08;Internet Protocol&#xff09;” ,IP协议是TCP/IP体系中的网络层协议。 总的来说&#xff0c;IP协议的最重要功能是提供了一种标准化的方式来路由和传输数据包&#xff0c;以实现全球互联网上的通信。 &#xff…

YOLOv7独家原创改进:新颖自研设计的BSAM注意力,基于CBAM升级

💡💡💡本文全网首发独家改进:提出新颖的注意力BSAM(BiLevel Spatial Attention Module),创新度极佳,适合科研创新,效果秒杀CBAM,Channel Attention+Spartial Attention升级为新颖的 BiLevel Attention+Spartial Attention 1)作为注意力BSAM使用; 推荐指数:…

数据结构构之顺序表

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线…

【halcon踩坑】区域为空但个数是1

背景 我在做瑕疵检测的时候&#xff0c;通过计算瑕疵区域的个数&#xff08;count_obj&#xff08;&#xff09;&#xff09;是否为0&#xff0c;来判断是否有瑕疵&#xff0c;如果不为0&#xff0c;那边我就会在图片上标记这个瑕疵的位置&#xff01; 但是有一次我发现明明没…

山西电力市场日前价格预测【2023-11-05】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-11-05&#xff09;山西电力市场全天平均日前电价为192.40元/MWh。其中&#xff0c;最高日前电价为374.84元/MWh&#xff0c;预计出现在04:15。最低日前电价为0.00元/MWh&#xff0c;预计出…

史上最详细的八大排序讲解(错过绝对后悔系列)建议先收藏再观看!—— 数据结构

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…

DB-GPT介绍

DB-GPT介绍 引言DB-GPT项目简介DB-GPT架构关键特性私域问答&数据处理多数据源&可视化自动化微调Multi-Agents&Plugins多模型支持与管理隐私安全支持数据源 子模块DB-GPT-Hub微调参考文献 引言 随着数据量的不断增长和数据分析的需求日益增多&#xff0c;将自然语言…

Docker 从 安装 到 配置 到 实战:手把手带你入门

文章目录 前言什么是docker&#xff1f;&#xff01;docker的作用是什么&#xff1f;&#xff01; 一、下载docker1.卸载docker2.安装yum环境3.更新yum本地软件源4.安装Docker&#xff08;参数ce&#xff1a;社区版&#xff09;5.Docker使用中会涉及到各种端口&#xff0c;为了…

为什么小程序做好了,却运营不起来?

​在小程序开发完成并投入市场后&#xff0c;许多商家发现小程序虽然做得很精美&#xff0c;但是却无法吸引到足够的用户&#xff0c;更谈不上留住用户了。那么&#xff0c;为什么小程序做好了却运营不起来呢&#xff1f;本文将就此问题进行探讨。 一、缺乏运营策略 很多商家在…

0002Java安卓程序设计-springboot合同管理APP论文

文章目录 摘 要目 录系统设计开发环境 摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c…

在Spring Boot中使用国产数据库连接池Druid

在我们实际开发过程中&#xff0c;我们经常使用的是DriverManager来获取&#xff0c;通过每次都向数据库建立连接时将Connection加载到内存中&#xff0c;然后验证用户名和密码&#xff0c;这段时间的消耗大致在0.0 5s - 1s左右&#xff0c;每次当我们需要获取数据库连接的时候…

“利用自动粘贴功能,一键粘贴网址,提升工作效率“

在快节奏的现代工作中&#xff0c;效率是关键。如果你经常需要复制和粘贴网址&#xff0c;那么你可能会浪费很多时间。幸运的是&#xff0c;我们的自动粘贴功能可以帮助你自动粘贴网址&#xff0c;一键即可完成&#xff0c;让你更加高效地工作。 首先&#xff0c; 我们要进入首…

操作系统复习(1)概述

一、序言 1.1简介 计算机系统组成&#xff1a;硬件操作系统 操作系统是计算机系统中的一个重要组成部分&#xff0c;它负责管理和控制计算机的硬件资源和软件资源&#xff0c;以及提供用户接口和其他功能 操作系统定义&#xff1a;操作系统是计算机系统中的一个系统软件&…

代码随想录算法训练营第23期day38|动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

目录 一、动态规划理论基础 1.动态规划的解题步骤 2.动态规划应该如何debug 二、&#xff08;leetcode 509&#xff09;斐波那契数 1.递归解法 2.动态规划 1&#xff09;确定dp数组以及下标的含义 2&#xff09;确定递推公式 3&#xff09;dp数组如何初始化 4&#x…

PMIC、电源管理MAX77646ANP、MAX77647AANP、MAX77675AEWE、MAX77847AEWL DC-DC 开关稳压器

一、MAX77646ANP、MAX77647AANP 低IQ SIMO PMIC支持原电池应用的1.8V工作电压 MAX77646/MAX77647为尺寸和效率至关重要的低功耗应用提供电源解决方案。该IC集成单电感多输出(SIMO)降压/升压稳压器&#xff0c;可通过单个电感提供三个可独立编程的电源轨&#xff0c;尽可能地减…

PageRank算法c++实现

首先用邻接矩阵A表示从页面j到页面i的概率&#xff0c;然后根据公式生成转移概率矩阵 M&#xff08;1-d&#xff09;*Qd*A 常量矩阵Q(qi,j),qi,j1/n 给定点击概率d&#xff0c;等级值初始向量R0&#xff0c;迭代终止条件e&#xff1b; 计算Ri1M*R…

选哪个内衣洗衣机比较好?觉飞和希亦内衣洗衣机对比测评

如今&#xff0c;随着物质生活水平的不断提升&#xff0c;消费者更加追求健康、品质化的生活。而反映在衣物清洁上&#xff0c;诸如像贴身衣物的深度清洁、儿童和成人衣物的分洗等细分场景下的洗护需求也变得越来越多&#xff0c;内衣物洗衣机也因此应运而生。现在市面上关于内…

【RabbitMQ】RabbitMQ 消息的堆积问题 —— 使用惰性队列解决消息的堆积问题

文章目录 一、消息的堆积问题1.1 什么是消息的堆积问题1.2 消息堆积的解决思路 二、惰性队列解决消息堆积问题2.1 惰性队列和普通队列的区别2.2 惰性队列的声明方式2.3 演示惰性队列接收大量消息2.4 惰性队列的优缺点 一、消息的堆积问题 1.1 什么是消息的堆积问题 消息的堆积…