数据结构-链表-单链表(3)

news2025/1/19 8:27:31

目录

1. 顺序表的缺陷

2. 单链表

2.1 单链表的基本结构与接口函数

2.2 重要接口

创建新节点的函数:

2.2.1 尾插

2.2.2 头插

2.2.3 尾删

2.2.4 头删

2.2.5 查找

2.2.6 插入

2.2.7 删除

2.2.8 从pos后面插入

2.2.9 从pos后面删除

3. 链表的缺陷与优势:

4. 链表与顺序表比较

写在最后:


1. 顺序表的缺陷

为什么会有链表?

我们都有顺序表来存储数据了,

因为顺序表是有缺陷的:

1. 中间头部插入删除数据,需要挪动数据,效率低下。

2. 空间不够需要扩容,扩容会有一定的消耗,也可能会造成空间的浪费。

这时候,我们就要用到链表。

2. 单链表

链表是一种物理存储结构上非连续、非顺序的存储结构,

数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

如下图: 

2.1 单链表的基本结构与接口函数

基本结构:

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;

typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLNode;

//打印链表
void SLPrint(SLNode* phead);

//尾插
void SLPushBack(SLNode** pphead, SLDataType x);

//头插
void SLPushFront(SLNode** pphead, SLDataType x);

//尾删
void SLPopBack(SLNode** ppheadx);

//头删
void SLPopFront(SLNode** pphead);

//查找
SLNode* SLFind(SLNode* phead, SLDataType x);

//插入
void SLInsert(SLNode** phead, SLNode* pos, SLDataType x);

//删除
void SLErase(SLNode** phead, SLNode* pos);

//从pos后面插入
void SLInsertAfter(SLNode* pos, SLDataType x);

//从pos后面删除
void SLEraseAfter(SLNode* pos);

2.2 重要接口

创建新节点的函数:

//建立一个新节点(重复操作写成函数复用)
SLNode* BuyNewNode(SLDataType x)
{
	//malloc一个链表节点大小的空间
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));

	//检查
	if (newnode == NULL)
	{
		perror("malloc::fail");
		return;
	}

	//赋值
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

2.2.1 尾插

//尾插
void SLPushBack(SLNode** pphead, SLDataType x)
{
	//检查二级指针pphead地址是否为空	
	//方便检查是否传空指针了
	assert(pphead);

	//创建节点
	SLNode* newnode = BuyNewNode(x);

	//如果链表为空
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else//如果链表不为空
	{
		//找尾
		SLNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		//尾插
		tail->next = newnode;
	}
}

2.2.2 头插

//头插
void SLPushFront(SLNode** pphead, SLDataType x)
{
	//检查二级指针pphead地址是否为空	
	//方便检查是否传空指针了
	assert(pphead);

	//创建节点
	SLNode* newnode = BuyNewNode(x);

	//头插
	newnode->next = *pphead;
	*pphead = newnode;
}

2.2.3 尾删

//尾删
void SLPopBack(SLNode** pphead)
{
	//检查二级指针pphead地址是否为空	
	//方便检查是否传空指针了
	assert(pphead);
	//检查链表是否为空
	assert(*pphead);
	
	//头删的情况(链表只有一个数据)
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		//找尾
		SLNode* tail = *pphead;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}

		//尾删
		free(tail->next);
		tail->next = NULL;
	}
}

2.2.4 头删

//头删
void SLPopFront(SLNode** pphead)
{
	//检查二级指针pphead地址是否为空	
	//方便检查是否传空指针了
	assert(pphead);
	//检查链表是否为空
	assert(*pphead);

	//头删
	SLNode* cur = (*pphead)->next;
	free(*pphead);
	*pphead = NULL;
	*pphead = cur;
}

2.2.5 查找

//查找
SLNode* SLFind(SLNode* phead, SLDataType x)
{
	//创建指针遍历链表
	SLNode* cur = phead;

	//查找
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

2.2.6 插入

//插入
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{
	//检查查找的地址是否为空
	assert(pos);

	//pos的位置
	if (pos == *pphead)
	{
		SLPushFront(pphead, x);
	}
	else//在链表中间
	{
		SLNode* prev = *pphead;

		//查找pos对应位置
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		//插入
		SLNode* newnode = BuyNewNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

2.2.7 删除

//删除
void SLErase(SLNode** pphead, SLNode* pos)
{
	//检查二级指针pphead地址是否为空	
	//方便检查是否传空指针了
	assert(pphead);

	//检查查找的地址是否为空
	assert(pos);

	//检查链表是否为空(这里其实不断言也可以)
	assert(*pphead);

	//头删的情况
	if (*pphead == pos)
	{
		SLPopFront(pphead);
	}
	else
	{
		//查找
		SLNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		//删除
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

2.2.8 从pos后面插入

//从pos后面插入
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	//检查查找的地址是否为空
	assert(pos);

	//创建节点
	SLNode* newnode = BuyNewNode(x);

	//再pos后面插入
	newnode->next = pos->next;
	pos->next = newnode;
}

2.2.9 从pos后面删除

//从pos后面删除
void SLEraseAfter(SLNode* pos)
{
	//检查查找的地址和要删除的地址是否为空
	assert(pos);
	assert(pos->next);

	//在pos后面删除,prev记住要删除的节点,然后free
	SLNode* prev = pos->next;
	pos->next = prev->next;
	free(pos->next);
	prev = NULL;
}

这就是单链表的基本框架和接口了,

如果感兴趣,你也可以使用接口函数玩一玩。

3. 链表的缺陷与优势:

但是链表是有缺陷的,

我们可以看到,

1. 链表想要访问一个节点,就得遍历链表,

2. 链表的尾删也需要遍历链表,

3. 而链表的优势是头删很方便是O(1)。

4. 链表与顺序表比较

我们就能跟顺序表比较一下,

1. 顺序表头插需要挪动数据是O(N),

2. 但是顺序表能随机访问。

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

之后我还会输出更多高质量内容,欢迎收看。

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

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

相关文章

传输数据格式:JSON 异步加载

JSON JSON是一种传输数据的格式&#xff08;以对象为样板&#xff0c;本质上就是对象&#xff0c;但用途有区别&#xff0c;对象就是本地用的&#xff0c;json是用来传输的&#xff09;JSON.parse();string --> jsonJSON.stringify();json --> string json ---> {n…

关于安卓的一些残缺笔记

安卓笔记Android应用项目的开发过程Android的调试Android项目文档结构Intent的显式/隐式调用Activity的生命周期1个Activity界面涉及到生命周期的情况2个Activity界面涉及到生命周期的情况Android布局的理论讲解Activity界面布局ContentProvider是如何实现数据共享Android整体架…

mysql视图和存储过程

视图视图就是将一条sql查询语句封装起来&#xff0c;之后使用sql时&#xff0c;只需要查询视图即可&#xff0c;查询视图时会将这条sql语句再次执行一遍。视图不保存数据&#xff0c;数据还是在表中。SELECT 语句所查询的表称为视图的基表&#xff0c;而查询的结果集称为虚拟表…

ATTCK v10版本战术实战研究—持久化(一)

一、前言“在网络安全的世界里&#xff0c;白帽子与黑帽子之间无时无刻都在进行着正与邪的对抗&#xff0c;似乎永无休止。正所谓&#xff0c;道高一尺魔高一丈&#xff0c;巨大的利益驱使着个人或组织利用技术进行不法行为&#xff0c;花样层出不穷&#xff0c;令人防不胜防。…

udk2017环境搭建编译步骤

win10 64bit系统 1.参考minnowboard-max-rel-1-01-bin-releasenotes-for-binary-firmware-images.TXT MyWorkspace.rar 解压到c:\&#xff0c;参考txt中的git操作 3.复制ASL,NASM 到c&#xff1a;\ 安装vs2015 &#xff0c;勾选sdk 5.安装 python-2.7.10.amd64.msi&#xf…

【论文泛读】NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis | NeRF: 用于视图合成的神经辐射场的场景表示 | 2020年 出自文献&#xff1a;Mildenhall B, Srinivasan P P, Tancik M, et al. Nerf: Representing scenes as neural radiance fields for view synth…

泼辣修图Polarr5.11.4 版,让你的创意无限延伸

泼辣修图是一款非常实用的图片处理软件&#xff0c;它不仅拥有丰富的图片处理功能&#xff0c;而且还能够轻松地实现自定义操作。泼辣修图的操作界面非常简洁&#xff0c;功能也非常丰富&#xff0c;使用起来非常方便快捷。 泼辣修图拥有非常丰富的图片处理功能&#xff0c;包括…

【冲刺蓝桥杯的最后30天】day1

大家好&#x1f603;&#xff0c;我是想要慢慢变得优秀的向阳&#x1f31e;同学&#x1f468;‍&#x1f4bb;&#xff0c;断更了整整一年&#xff0c;又开始恢复CSDN更新&#xff0c;从今天开始逐渐恢复更新状态&#xff0c;正在备战蓝桥杯的小伙伴可以支持一下哦&#xff01;…

Rockchip Android13 GKI开发指南

Rockchip Android13 GKI开发指南 文章目录Rockchip Android13 GKI开发指南GKI介绍Google upstream kernel下载及编译Rockchip SDK中GKI相关目录介绍Rockchip GKI编译代码修改编译固件烧写KO编译及修改添加新的模块驱动的方法调试ko方法开机log确认uboot阶段Android阶段KO加载KO…

Java IO流详解

文章目录一、File1.1 构造方法1.2 文件操作 方法1.3 目录操作 方法1.4 文件检测 方法1.5 获取文件信息 方法1.6 应用练习二、IO 流2.1 InputStream 字节输入流 (读)&#x1f353;FileInputStream&#x1f353;BufferedInputStream2.2 OutputStream 字节输出流 (写)&#x1f34c…

【Redis】redis大key和大value的危害,如何处理?

前序 还记得上次和同事一起去面试候选人时&#xff0c;同事提了一个问题&#xff1a;Redis的大key有什么危害&#xff1f;当时候选人主要作答的角度是一个key的value较大时的情况&#xff0c;比如&#xff1a; 内存不均&#xff1a;单value较大时&#xff0c;可能会导致节点之…

[经验分享]gpt-3.5-Turbo|unity中实现http接口调用gpt新接口以及信息处理的实现案例分享

最近openAI发布了目前chatGPT所使用的模型gpt-3.5-Turbo&#xff0c;之前使用了text-davinci-003模型做了一个galgame的AI女友对话的demo。这次趁着新接口的发布&#xff0c;对这个demo也同步更新了模型调用的代码。本篇文章将分享一下&#xff0c;如何在unity里使用UnityWebRe…

记录一次PWM信号异常问题

问题我使用单片机输出PWM控制机械臂&#xff0c;但是控制过程中&#xff0c;机械臂总是会出现莫名的抽动。利用示波器测试PWM信号&#xff0c;发现信号正常。过程&#xff08;1&#xff09;在反复的测试过程中&#xff0c;队友提出&#xff0c;将示波器的地线放在左侧的GND波形…

计算机EI会议论文,和EI期刊论文有什么区别? - 易智编译EaseEditing

EI期刊论文&#xff0c;是期刊论文的一种。顾名思义&#xff0c;就是指发在期刊上的论文。 期刊论文发表的格式需要具体参考各期刊文章的要求学术论文格式&#xff0c;主要会发在月刊/季刊/年刊/不定期的刊上。 目前&#xff0c;国际著名的科技文献检索系统是SCI&#xff08;…

安卓-AndroidManifest.xml修复

解析编译之后的AndroidManifest文件格式&#xff1a;http://www.520monkey.com/archives/575 案例apk jadx打开发现AndroidManifest.xml异常&#xff0c;无法正常显示 那么我们用apktool反编译试试 apktool d APK逆向-2.apk -f可以看到报错了&#xff0c;显示不能解析此xml…

[SSD科普] 固态硬盘物理接口SATA、M.2、PCIe常见疑问,如何选择?

前言犹记得当年Windows 7系统体验指数中&#xff0c;那5.9分磁盘分数&#xff0c;在其余四项的7.9分面前&#xff0c;似乎已经告诉我们机械硬盘注定被时代淘汰。势如破竹的SSD固态硬盘&#xff0c;彻底打破了温彻斯特结构的机械硬盘多年来在电脑硬件领域的统治。SSD数倍于HDD机…

数据结构 “串“ 的补充提升与KMP算法及其优化的具体实现

❤️作者主页&#xff1a;微凉秋意 ✅作者简介&#xff1a;后端领域优质创作者&#x1f3c6;&#xff0c;CSDN内容合伙人&#x1f3c6;&#xff0c;阿里云专家博主&#x1f3c6; ✨精品专栏&#xff1a;C面向对象 &#x1f525;系列专栏&#xff1a;数据结构与课程设计 文章目录…

XSS漏洞基本概念

目录 XSS的原理和分类 XSS漏洞分类 dom 存储型 XSS的危害 XSS漏洞的验证 XSS的黑盒测试 XSS漏洞的白盒测试 XSS的原理和分类 xss全称跨站脚本攻击xss&#xff08;Cross Site Scripting&#xff09; 为了不和层叠样式表&#xff08;Cascading Style Sheets, CSS)的缩写混淆&am…

MCU实现对外部脉冲信号的计数功能

有的传感器会输出脉冲信号&#xff0c;MCU需要统计脉冲输入的个数&#xff0c;通常有如下实现方式&#xff1a; 1.GPIO中断 原理很简单&#xff0c;利用GPIO的上升沿或者下降沿中断&#xff0c;进中断的次数就是脉冲的个数。只需要在中断服务函数里计数即可。 使用GPIO中断需…

Streaming System是第一章翻译

GIthub链接&#xff0c;欢迎志同道合的小伙伴一起翻译 Chapter 1.Streaming101 如今&#xff0c;流数据处理在大数据中是非常重要的&#xff0c;其主要原因是&#xff1a; 企业渴望对他们的数据有更及时的了解&#xff0c;而转换到流处理是实现更低延迟的一个好方法&#xf…