初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

news2024/11/25 15:00:14

本章概述

  • 前情回顾
  • 单链表
  • 实现单链表
  • 彩蛋时刻!!!

前情回顾

咱们在上一章博客点击:《顺序表》的末尾,提出了一个问题,讲出了顺序表的缺点——有点浪费空间。所以,为了解决这个问题,我们今天就要讲解链表,咱们在讲结构体的时候有提到过链表,链表的最大优点——一点空间也不浪费,用多少就开辟多少在这里插入图片描述

单链表

  • 概念一种在逻辑上成线性结构,在物理空间上不一定成线性结构的数据结构因为链表是线性表的一种,所以在逻辑上成线性结构“ 链 ”字上就能猜到,在逻辑上成线性结构)。我们链表的开辟用的内存函数malloc。知识点忘记的同学自行回顾:点击:《动态内存管理》。因为内存开辟是随机的,所以我们也不知道它会在内存的那一块区域开辟空间,这就导致开辟的空间可能是连续的,也可能不是连续的。所以,在物理空间上不一定成线性结构。在这里插入图片描述
  • 节点每一个个独立,而且还能存放数据的空间被称为节点。数据结构是用来存储数据的,链表自然也是来存储数据的。存储数据就需要有空间,自然有malloc来给我们开辟空间。万事俱备,只欠东风!可是有想过一个问题吗?——malloc开辟的空间东一块,西一块的它不像realloc那样开辟的连续空间(我们可以挨着挨着找到空间),它的空间是散乱的,不连续的。那么,我们该怎样进行数据的存储,而且还能找到一个一个的数据呢我们可以在这个节点内部划分两部分,一部分用来存储我们想要存储的数据,另一部分部分用来存储下一个节点的地址(因为我们的节点空间是用nalloc开辟的,所以每个节点自然就有个地址)这就需要用到结构体了,进行链表的结构展示:
typedef int SLDatatype ;
typedef struct  Sqlist
{
		SLDatatype data;	//存放数据,这里假设存放整型类型
		struct Sqlist* next;   //存放下一个节点的地址
}SLND;		  //定义节点类型

这样我们就能通过地址找到下一个节点了,以此类推,我们就能顺次找到各个节点,找到数据了。如图所示:在这里插入图片描述
当我们不想再存储数据时,要给最后一个节点的next指针赋值NULL(下一个节点为NULL,就相当于没有下一个节点),就表示到此结束了。

  • 链表的性质
    • 1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续。
    • 2、结点⼀般是从堆上申请的。
    • 3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续。
  • 链表的打印:我们讲过了节点的存储结构了,我们可以通过next指针,找到下一个节点,然后就能打印我们想要的数据了。
  • 直观体验链表:我们先给大家直观感受一下链表,让大家有个感觉,我们就按照上面的结构图进行展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLDatatype;
typedef struct Sqlist
{
	SLDatatype data;
	struct Sqlist* next;
}SLND;

void my_printf(SLND* ps)
{
	assert(ps);
	while (ps)
	{
		printf("%d->", ps->data);
		ps = ps->next;
	}
	printf("NULL");
}
void test()
{
	SLND* plist=NULL;  //创立一个带头指针,用来牵引后面的链表,就像火车头一样
	SLND* node1 = (SLND*)malloc(sizeof(SLND));   //创立3个节点
	SLND* node2 = (SLND*)malloc(sizeof(SLND));
	SLND* node3 = (SLND*)malloc(sizeof(SLND));

	node1->data = 1;  //分别对3个节点·进行·数据的存储
	node2->data = 2;
	node3->data = 3;

	node1->next = node2;  //每个节点的next的指针指向下一个节点的地址
	node2->next = node3;
	node3->next = NULL;

	plist = node1;
	my_printf(plist);
}
int main()
{
	test();
	return 0;
}

结果运行图:在这里插入图片描述
我们的指针plist就是个牵引的作用,就像高铁一样,没有高铁头车厢照样能跑,就是不美观,没有它也可以正常访问链表。有了它就是逻辑上和美观上要舒服很多。如图所示:在这里插入图片描述

实现单链表

和顺序表一样,我们也是创建3个文件: Sqlist .h , Sqlist.ctest .c文件。具体的原因个顺序表一样的。接下来我直接给大家展示代码,我会在注释中详细讲解的。

  • Sqlist.h:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SListDatatype;
typedef struct SListNode
{
	SListDatatype data;
	struct SListNode* next;
}SLND;

SLND* SListFind(SLND* phead, SListDatatype x);//找对应的节点
SLND* SLTButnode(SListDatatype x);//申请新的节点
void my_printf(SLND* phead); //·打印链表信息

void SListpushback(SLND** pphead, SListDatatype x); //尾插
void SListpopback(SLND** pphead);//尾删

void SListpushFront(SLND** pphead, SListDatatype x); //头插
void SListpopFront(SLND** pphead);//头删

void SListrdFrontpush(SLND** pphead, SLND* find, SListDatatype x);//在任意节点之前插入数据
void SListrdBackpush(SLND* find, SListDatatype x);//在任意节点之后插入数据

void SListposePop(SLND* phead, SLND* pose); //删除指定节点
void SListDestry(SLND** pphead); //销毁链表
  • Sqlist.c:
#include "SList.h"
//打印链表信息
void my_printf(SLND* phead)   //打印信息,便于我们看信息的输出
{
	SLND* pcur = phead;
	while (pcur)
	{
		printf("%d-> ",pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n"); //第N+1个为空====没有链表
}
SLND * SLTButnode(SListDatatype x)	//申请新空间,返回新空间地址,便于咱们找到新空间插入数据
{
	SLND* newnode = (SLND*)malloc(sizeof(SLND));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);		//若开辟失败就直接退出程序,也可以写成 return 1;
	}
	else{
		newnode->data = x;  	//走到这里就开辟成功,进行初始化
		newnode->next = NULL;
	}
		return newnode;
}
void SListpushback(SLND** pphead, SListDatatype x) //尾插数据
{
	assert(pphead);  //检查传递的指针是否为空指针
	SLND* newnode = SLTButnode(x);
	if (*pphead==NULL)  
	{
		*pphead = newnode;	//如果起始没有节点,先创立个节点
	}
	else{
		SLND* ptail = *pphead;
		while (ptail->next)      //遍历节点,找到最后一个节点的next为空的情况,跳出循环
		{
			ptail = ptail->next;  
		}
		ptail->next = newnode;  //走到这里说明找到了最后一个节点,在此之后插入新的节点
	}
}
void SListpopback(SLND** pphead) //尾删数据
{
	assert(pphead&&*pphead);  //检查传递的指针是否为空指针   
	SLND* ptail = *pphead;  //我们把起始节点的地址给ptail,用ptail进行遍历数据,去寻找最后的尾节点
	SLND* prev = NULL;   //prev是用来记录尾节点前一个节点,不记录的话,就会随着我们删除最后一个节点而丢失信息
	while (ptail->next)
	{
		prev = ptail;
		ptail = ptail->next;
	}
	prev->next = NULL;
	free(ptail);  //找到最后一个节点,进行空间释放
	ptail = NULL;  //释放后要置空,防止产生野指针
}
void SListpushFront(SLND**pphead,SListDatatype x) //头插数据
{
	assert(pphead);  //判断传递的地址是否为空指针
	SLND* newnode = SLTButnode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}
void SListpopFront(SLND**pphead)//头删
{
	assert(pphead&&*pphead);	//判断传递的地址是否为空指针
	SLND*next = (*pphead)->next;
	free(*pphead);  //释放头节点
	*pphead = next;  //释放头节点后,要使得plist指向第二个节点
}
SLND* SListFind(SLND*phead,SListDatatype x) //找对应的节点
{
	assert(phead); 	//判断传递的地址是否为空指针
	while (phead)
	{
		if (phead->data == x)
			return phead;    //找到目标节点,就返回目标节点的地址
		phead = phead->next;
	}
	return NULL;  //没找到就返回空指针
}
void SListrdFrontpush(SLND**pphead,SLND*find,SListDatatype x)//在任意节点之前插入数据
{
	assert(pphead&&*pphead);		//判断传递的地址是否为空指针
	if (*pphead == find)    //任意位置刚好是头节点时,相当于头插数据
		SListpushFront(pphead, x); //头插数据
	else {
		SLND*newnode= SLTButnode(x);//申请新的节点
		SLND* prev = NULL;
		SLND* ptail = *pphead;
		while (ptail!= find)
		{
			prev = ptail;
			ptail = ptail->next;
		}
		prev->next = newnode;  //指定位置之前的节点的next指针指向要插入的新节点
		newnode->next = ptail;		//这个新节点的next指针指向下一个节点
	}
}
void SListrdBackpush( SLND* find, SListDatatype x)//在任意节点之后插入数据
{
	assert(find);		//判断传递的地址是否为空指针
	SLND* newnode = SLTButnode(x);
	newnode->next = find->next;  //新节点的next指针指向下一个节点
	find->next = newnode;		//新节点之前的节点next指针指向这个新节点
}
void SListposePop(SLND**pphead, SLND* pose) //删除指定节点
{
	assert(*pphead&&pose);		//判断传递的地址是否为空指针
	if(pose==*pphead)		//当删除的节点是头节点时,就相当于头删
		SListpopFront(pphead);//头删
	else
	{
		SLND* prev = NULL;	
		SLND* ptail = *pphead;
		while (ptail != pose)		//遍历节点,找到目标节点
		{
			prev = ptail;
			ptail = ptail->next;
		}
		SLND* next = ptail->next;	
		prev->next = next;
		free(ptail);  //删除指定的节点
		ptail = NULL;    //置空指针,防止发生野指针
	}
}

//链表的销毁和顺序表不一样
void SListDestry(SLND**pphead) //链表的销毁不像顺序表那样直接释放内存就欧克,因为每个
{							//节点都是独立的,所以我们需要去遍历每个节点去销毁
	assert(*pphead);		//判断传递的地址是否为空指针
	SLND* prev = NULL;
	SLND* ptail = *pphead;
	while (ptail->next) //一直遍历到最后一个节点才结束
	{
		prev = ptail;
		ptail = ptail->next;
		free(prev); //每遍历一个节点就释放
		prev = NULL;  //置空指针防止产生野指针
	}
	ptail = NULL;		//置空指针防止产生野指针
	*pphead = NULL;	//置空指针防止产生野指针
}
  • test.h
#define  _CRT_SECURE_NO_WARNINGS	1
#include "SList.h"
void test()
{		//这里给大家演示一下尾插数据,其它功能大家可以自行尝试一下
	SLND* plist = NULL;
	SListpushback(&plist,1);//尾插
	SListpushback(&plist,2);//尾插
	SListpushback(&plist,3);//尾插
	SListpushback(&plist,4);//尾插
	my_printf(plist);
}

int main()
{
	test();
	return 0;
}

结果运行图:在这里插入图片描述

彩蛋时刻!!!

歌曲:《All Falls Down》听会儿歌曲放松一下呗!!!
在这里插入图片描述
每章一句道路是曲折的,前途是光明的!感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!

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

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

相关文章

计算机网络-RSTP快速生成树基础概念

一、STP概念复习 在之前的学习中我们已经学习了STP的概念与作用。参考文章&#xff1a;计算机网络-生成树基础 STP&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09; 是一种用于在局域网中消除数据链路层物理环路的协议。主要作用是防止交换机冗余链路产生…

app端文章列表查询-详细教程(上)

app端文章列表查询 一、数据库方面 有关文章的表垂直拆分成了三张表&#xff1a;文章基本信息表&#xff08;字段有文章id、文章作者、文章标题、发布时间等&#xff09;、文章配置表&#xff08;字段有文章id、文章是否可评论、文章可转发、是否已下架、是否已删除等&#x…

MySQL 基础查询

1、DISTINCT select DISTINCT EMPLOYEE_ID ,FIRST_NAME from employees 按照ID去重&#xff0c;DISTINCT的字段要放在前面&#xff0c;不会再继续在FIRST_NAME上去重判断&#xff1b; 如果需要多字段去重&#xff0c;需要用到group by&#xff0c;这个后面讲&#xff1b; …

【Fargo】11: pacing 参数不生效:同步调整采集码率

发送侧参数改变 接收测没感觉到 还是2秒收到60个不变: 果然,发送侧的参数设置没生效 发送的码率终于正确了

【C++、数据结构】二叉排序树(二叉查找树、二叉搜索树)(图解+完整代码)

目录 [⚽1.什么是二叉排序树] [&#x1f3d0;2.构建二叉排序树] [&#x1f3c0;3.二叉排序树的查找操作] [&#x1f94e;4.二叉排序树的删除] [&#x1f3b1;5.完整代码] ⚽1.什么是二叉排序树 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是…

【慕伏白教程】将 Windows11 装进口袋 -- 便携式 Windows 11 制作教程

目录 下载 Windows 11 镜像下载 Rufus开始安装 Windows 11 下载 Windows 11 镜像 打开微软 Windows 11 官方下载网站&#xff0c;找到 下载适用于 x64 设备的 Windows 11 磁盘映像 (ISO) 根据个人情况选择要下载的磁盘镜像&#xff0c;选择多版本 ISO 的话可在安装系统开始时进…

多IP连接

一.关闭防火墙 systemctl stop firewalld setenforce 0 二.挂在mnt mount /dev/sr0 /mnt 三.下载nginx dnf install nginx -y 四.启动nginx协议 systemctl start nginx 五.修改协议 vim /etc/nginx/nginx.conf 在root前加#并且下一行添加 root /www:&#xff08;浏…

基于图像拼接开题报告

选题的背景与意义 在日常生活中&#xff0c;使用普通相机获取宽视野的场景图像时&#xff0c;必须通过调节相机的焦距才可以提取完整的场景。由于相机的分辨率有限&#xff0c;拍摄场景越大&#xff0c;得到的图像分辨率就越低&#xff0c;因此只能通过缩放相机镜头减小拍摄的…

应对 .DevicData-X-XXXXXXXX 勒索病毒:防御与恢复策略

引言 随着信息技术的快速发展&#xff0c;网络安全问题愈发严峻。勒索病毒作为一种恶性网络攻击手段&#xff0c;已成为企业和个人面临的重大威胁之一。尤其是 .DevicData-X-XXXXXXXX 勒索病毒&#xff0c;其通过加密用户数据并勒索赎金&#xff0c;给受害者带来了巨大的经济损…

dolphinscheduler创建工作流及工作流中DataX的使用(简单操作)

一、在项目管理中创建项目&#xff1a;点击创建项目 用哪个用户登录的&#xff0c;所属用户就是哪个&#xff0c;直接输入项目名即可 二、点击项目&#xff0c;在项目中创建工作流&#xff0c;用DataX同步数据 按照图片的步骤依次填写完成&#xff0c;注意 图片中的第九步是写…

个税自然人扣缴客户端数据的备份与恢复(在那个文件夹)

一&#xff0c;软件能够正常打开&#xff0c;软件中的备份与恢复功能 1&#xff0c;备份 您按照下面的方法备份一下哦~ 进入要备份的自然人软件&#xff0c;点击左侧系统设置→→系统管理→→备份恢复&#xff1b; 在备份设置里&#xff0c;点击“备份到选择路径”&#xff0c;…

小白向的源码开发详解:直播带货系统与电商平台搭建指南

本篇文章&#xff0c;笔者将为小白们提供一份详细的源码开发指南&#xff0c;帮助你轻松搭建自己的直播带货系统和电商平台。 一、了解直播带货系统的基本构成 直播带货系统主要由以下几个部分组成&#xff1a; 1.前端界面 2.后端服务器 3.数据库 4.直播平台 二、技术选型…

【C++】— 一篇文章让你认识STL

文章目录 &#x1f335;1.什么是STL&#xff1f;&#x1f335;2.STL的版本&#x1f335;3.STL的六大组件&#x1f335;4.STL的重要性&#x1f335;5. 如何学习STL&#x1f335;6. 学习STL的三种境界 &#x1f335;1.什么是STL&#xff1f; STL是Standard Template Library的简称…

深入理解Redis锁与Backoff重试机制在Go中的实现

文章目录 流程图Redis锁的深入实现Backoff重试策略的深入探讨结合Redis锁与Backoff策略的高级应用具体实现结论 在构建分布式系统时&#xff0c;确保数据的一致性和操作的原子性是至关重要的。Redis锁作为一种高效且广泛使用的分布式锁机制&#xff0c;能够帮助我们在多进程或分…

Vue+ECharts+iView实现大数据可视化大屏模板

Vue数据可视化 三个大屏模板 样式还是比较全的 包括世界地图、中国地图、canvas转盘等 项目演示&#xff1a; 视频&#xff1a; vue大数据可视化大屏模板

神经网络模型内部

给大家展示一个三层4*24*24*2神经网络文件的内部&#xff1a; 大小5.06KB 想知道这个模型是怎么训练生成的看我的上一篇文章 用神经网络自动玩游戏

Centos7安装ZLMediaKit

https://github.com/ZLMediaKit/ZLMediaKit 一 获取代码 git clone https://gitee.com/xia-chu/ZLMediaKit cd ZLMediaKit git submodule update --init git submodule update --init 命令用于初始化和更新 Git 仓库中的子模块&#xff08;submodules&#xff09;。这个命令…

vue3 + ts + element-plus 二次封装 el-dialog

实现效果&#xff1a; 组件代码&#xff1a;注意 style 不能为 scoped <template><el-dialog class"my-dialog" v-model"isVisible" :show-close"false" :close-on-click-modal"false" :modal"false"modal-class&…

web网页QQ登录

代码&#xff1a; <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>QQ登录ent</title> </head> <style>ul > li{list-style: none; } a …

U盘数据丢失不用慌,这4个工具可以帮你恢复。

因为将大量的数据存到U盘里面很方便&#xff0c;所以U盘使用也很广泛。但是里面的数据丢失想必很多朋友都碰到过&#xff0c;不过现在有很多方法都可以帮助大家将数据回顾回来。这里我便筛选了几款比较好的数据恢复工具&#xff0c;在这里跟大家分享。 1、福昕U盘恢复软件 直通…