C语言实现单链表(图解增删查改+代码)

news2024/11/18 5:38:19

文章目录

  • 写在前面
  • 1. 链表节点的定义
  • 2. 链表的创建
  • 3. 插入数据
    • 3.1 头插
    • 3.2 尾插
    • 3.3 在指定位置的前面插入数据
  • 4. 删除数据
    • 4.1 头删
    • 4.2 尾删
    • 4.3 删除指定位置的数据
  • 5. 查找数据
  • 5. 链表的销毁

写在前面

上面文章用C语言实现了顺序表的增删查改,本片文章继续用C语言来实现另一种线性存储结构——单链表。我们知道,顺序表中的数据元素在内存中是连续存储的,而单链表的数据元素在内存中是随机存储的。它由节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。
例如:使用单链表存储 {1,2,3,4,5},数据在内存中的存储状态的逻辑图如下所示:
在这里插入图片描述
总结:单链表的数据元素在内存中随机存储,数据元素之间的逻辑关系是通过指针来表示的

1. 链表节点的定义

链表的结点分为两部分:数据域和指针域
数据域:链表要存储的数据所在的区域。
指针域:指向下一个节点的指针所在的区域。
在这里插入图片描述
链表节点的定义:

typedef int SLTDatatype;

typedef struct SListNode
{
	SLTDatatype data;//数据域
	struct SListNode* next;//指针域, 指向下一个节点
}SLTNode;

2. 链表的创建

创建一个新链表,通常包括一个指向链表头节点的指针,初始时指向NULL。
例如:一个存储 {1,2,3,4,5} 的链表结构下如图所示:
在这里插入图片描述
该链表是由头指针 plist 来维护的,通过头指针 plist 就能找到该链表。由于链表刚创建的时候,链表中没有节点,因此链表创建时,plist 为空。
创建头指针的代码如下:

SLTNode* plist = NULL;//创建头指针

3. 插入数据

向链表插入数据时,根据插入位置的不同可以分为以下三种情况:

  • 在头节点前插入一个元素,即头插。
  • 在链表中间位置插入元素。
  • 在最后一个节点后面插入一个元素,即尾插。

3.1 头插

头插数据步骤:

  • 新建一个节点。
    由于后面的插入都需要创建新的节点,因此这里把创建节点封装成一个函数。

代码如下:

//创建新节点
SLTNode* BuyNode(SLTDatatype x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("BuyNode->malloc");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
  • 新节点的 next 指向 plist 指向的节点。
  • plist 指向新节点。
    在这里插入图片描述

代码如下:

void SLTPushFront(SLTNode** pphead, SLTDatatype x)
{
	assert(pphead);//检查参数的有效性
	//创建节点
	SLTNode* newnode = BuyNode(x);
	
	newnode->next = (*pphead);
	*pphead = newnode;
}

3.2 尾插

尾插数据分为以下两种情况:

  1. 链表为空
  • 新建一个节点。
  • 新节点的 next 指向 NULL。
  • plist 指向新节点。
    在这里插入图片描述
  1. 链表不为空
  • 新建一个节点。
  • 遍历链表,找到最后一个节点
  • 新节点的 next 指向 NULL。
  • 最后一个节点的 next 指向新节点。
    在这里插入图片描述

代码如下:

void SLTPushBack(SLTNode** pphead, SLTDatatype x)
{
	assert(pphead);//检查参数有效性
	SLTNode* newnode = BuyNode(x);
	//链表为空的情况
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		//链表不为空的情况
		SLTNode* cur = *pphead;
		//遍历链表,找最后一个节点
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}

3.3 在指定位置的前面插入数据

步骤如下:

  • 新建一个节点。
  • 遍历链表,找到指定位置pos的前一个节点prev。
  • 新节点的 next 指向pos。
  • prev的 next 指向新节点。

在这里插入图片描述
代码如下:

void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDatatype x)
{
	assert(pphead);//检查参数的有效性
	assert(pos);//检查插入位置的有效性
	SLTNode* newnode = BuyNode(x);

	//头插
	if (*pphead == pos)
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}
	else
	{
		//中间位置插入数据
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		newnode->next = pos;
		prev->next = newnode;
	}
}

4. 删除数据

4.1 头删

头删的步骤如下:

  • 判断链表是否为空,不为空在进行删除。
  • 保存头节点的地址。
  • 更新 plist ,使其跳过待删除节点,指向待删除节点的下一个节点。
  • 释放头节点的内存。
    在这里插入图片描述

代码如下:

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);//检查参数有效性
	assert(*pphead);//检查链表是否为空

	SLTNode* phead = *pphead;
	*pphead = phead->next;
	free(phead);
}

4.2 尾删

尾删的步骤如下:

  • 判断链表是否为空,不为空在进行删除。
  • 找到最后一个节点的前一个节点prev。
  • 保存待删除节点的地址。
  • prev 的 next 指向NULL。
  • 释放头节点的内存。

在这里插入图片描述
代码如下:

void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);//检查参数有效性
	assert(*pphead);//检查链表是否为空
	
	//只有一个元素时,相当于头删
	if ((*pphead)->next == NULL)
	{
		SLTNode* phead = *pphead;
		*pphead = phead->next;
		free(phead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next->next != NULL)
		{
			prev = prev->next;
		}
		SLTNode* ptail = prev->next;
		prev->next = NULL;
		free(ptail);
	}
}

4.3 删除指定位置的数据

  • 判断链表是否为空,不为空在进行删除。
  • 找到待删除节点的前一个节点。
  • 更新前一个节点的指针,使其跳过待删除节点,指向待删除节点的下一个节点。
  • 释放待删除节点的内存。

在这里插入图片描述
代码如下:

void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);//检查参数有效性
	assert(*pphead);//检查链表是否为空
	//头删
	if (*pphead == pos)
	{
		SLTNode* phead = *pphead;//保存头节点的指针
		*pphead = phead->next;
		free(phead);
		//SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

5. 查找数据

在链表中查找指定数据的方法是:从表头开始依次遍历链表的节点,如果被查找数据与当前遍历节点的数据相同就是查找成功,如果遍历完链表都没找到,则查找失败。

  • 如果找到了,就返回数据所在节点的地址
  • 如果找不到,则返回 NULL。

代码如下:

SLTNode* SLTFind(SLTNode* phead, SLTDatatype x)
{
	SLTNode* cur = phead;
	//遍历链表的每一个节点
	while (cur)
	{
		//与每个节点的数据进行比较
		if (cur->data == x)
		{
			return cur;
		}
	}
	return NULL;
}

5. 链表的销毁

依次释放链表的每个节点。
代码如下:

void SLTDestroy(SLTNode** pphead)
{
	assert(pphead); //检查参数的有效性
	SLTNode* cur = *pphead;
	SLTNode* next = NULL;

	if (cur)
	{
		next = cur->next;
	}
	while (cur)
	{
		free(cur);
		cur = next;
		if (cur)
		{
			next = cur->next;
		}
	}
	*pphead = NULL;
}

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !!!在这里插入图片描述

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

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

相关文章

web各个指标理解

QPS : 单位时间得请求次数 TPS :单位时间得事务数 并发 : QPS *单位响应时间 pv :进入一个网站,又单击打开该网站的其他页面,每打开一个页面就 增加一个PV,甚至在同一页面每刷新一次也多一个PV 二八定律:百…

nonaDlA 逻辑分析仪 使用记录

注意事项,很灵敏,不要用手碰,产生误触发 安装软件 github地址 官方提供的淘宝地址与使用说明 1.安装 1.安装程序 :下载githubDLA源码,打开 software\PulseView.exe安装 2.安装驱动:安装完第一步后&a…

【OpenVINO】行人摔倒检测 — 基于 OpenVINO C# API 部署PP-Human-下篇

行人摔倒检测 — 基于 OpenVINO C# API 部署PP-Human 4. 配置 PP-Human_Fall_Detection 项目4.1 环境配置4.2 创建 AlxBoard_deploy_yolov8 项目4.3 添加项目源码4.4 添加 OpenVINO C# API4.5 添加 OpenCvSharp 5. 测试 PP-Human_Fall_Detection 项目5.1 创建视频读取器5.2 行人…

Python南瓜头

系列文章 ​​​​​​​ 序号文章目录直达链接1浪漫520表白代码https://want595.blog.csdn.net/article/details/1306668812满屏表白代码https://want595.blog.csdn.net/article/details/1297945183跳动的爱心https://want595.blog.csdn.net/article/details/1295031234漂浮…

生成二维码

Qt本地生成二维码-第三方库Libqrencode Chapter1 Qt本地生成二维码-第三方库Libqrencode一、功能简介二、本地生成二维码三、在线生成二维码 Chapter2 Qt生成二维码图片方法QRCode二维码简介如何选定QR码版本?主要方法(1) 下载qrencode源码(2) 将qrencode源码移植到…

C++ STL六大组件

目录 前言 一、容器 1 向量 1.1 向量(Vector)和数组(array)之间的区别 1.2 语法 1.3 示例 1.3.1 创建 vector 对象 1.3.2 不能打印向量对象;不能打印空向量中的元素,因为空向量中无元素可打印 1.3…

又哭又笑,这份面试宝典要是早遇到就好了

01、算法原理 选择排序(Selection sort)是一种简单直观的排序算法。 第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素&#…

filebeat(8.9.0)采集日志到logstash,由logstash发送的es

filebeat采集日志到logstash,由logstash发送的es 下载并配置filebeat下载配置logback.xml logstash配置 下载并配置filebeat 下载 参考 配置 filebeat.inputs: - type: filestreamenabled: truepaths:# 日志文件目录- D:\modellog\elkdemo\*\*.logparsers:# 多…

消息队列 RocketMQ 消息重复消费问题(原因及解决)

目录 1.出现重复消费的原因 2.解决 2.1 数据库插入法 2.2 使用布隆过滤器 2.2.1 添加hutool的依赖 2.2.2 测试生产者 2.2.2 测试消费者 1.出现重复消费的原因 BROADCASTING(广播) 模式下,所有注册的消费者都会消费,而这些消费者通常是集群部署的…

hdlbits系列verilog解答(内部wire)-09

文章目录 wire线网类型介绍一、问题描述二、verilog源码三、仿真结果wire线网类型介绍 wire线网类型是verilog的一种数据类型,它是一种单向的物理连线。它可以是输入也可以是输出,它与reg寄存器数据类型不同,它不能存储数据,只能用于组合逻辑建模。常用于assign连续赋值语…

测试饱和了? 大数据测试就业薪资和前景究竟怎么样?

随着不断有转行人员及毕业的大学生进入IT行业,在很多外界人眼里,这个行业的“缺口”已满,人员趋于饱和,但事实真的这样吗?还真没有。只是最基础的岗位需求在慢慢变少了,但行业中比较深的细分岗位&#xff0…

一、软件工程概述+练习题

文章目录 软件工程复习一、 概述1.常见考点1.1 什么是软件?软件的特点 1.2 什么是软件危机?它的具体表现是什么?软件危机的概念软件危机的内容具体表现软件危机的原因消除软件危机的途径 2.软件工程的三要素软件工程的定义 3. 软件生存周期4.…

在软件测试行业这种情况下,凭什么他能拿25k?我却约面试都难?

在当今竞争激烈的软件测试行业中,近期的招聘市场确实面临一些挑战。大量的求职者争相涌入岗位,许多热衷于功能测试的人士甚至难以找到理想的工作机会。更不幸的是,连自动化测试和性能测试这些专业领域也受到了测试开发人员的竞争压力。然而&a…

HashMap遍历之EntrySet————小练习

public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("jack",650);hashMap.put("tom",1200);hashMap.put("smith",2900);System.out.println(hashMap);//将jack的工资更改为2600hashMap.put("jack",…

基于ElasticSearch+Vue实现简易搜索

基于ElasticSearchVue实现简易搜索 一、模拟数据 产品名称描述价格库存数量品牌名称智能手表智能手表,具有健康跟踪和通知功能。199.991000TechWatch4K智能电视4K分辨率智能电视,提供出色的画质。699.99500VisionTech无线耳机降噪无线耳机,…

《低代码指南》——维格云和Airtable的比较

Airtable​ 什么是Airtable​ Airtable 是一个任务管理应用程序,它合并了电子表格、数据存储和模板,以帮助组织构建他们的工作流程。 适用于哪些企业/组织/人群​ 根据 Airtable 网站,该工具被超过 200,000 个组织的团队使用。 维格表与Airtable相比如何​ Airtable作为…

【C语言】善于利用指针(三)

💗个人主页💗 ⭐个人专栏——C语言初步学习⭐ 💫点击关注🤩一起学习C语言💯💫 目录 导读:1. 函数指针1.1 什么使函数指针1.2 用函数指针变量调用函数 2. 返回指针值的函数3. 函数指针数组3.1 实…

asp.net社区医疗辅助诊断网站系统VS开发sqlserver数据库web结构c#编程

一、源码特点 asp.net社区医疗辅助诊断网站系统 是一套完善的web设计管理系统,系统采用mvc模式(BLLDALENTITY)系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver200…

音乐制作软件 Ableton Live 11 Suite mac中文版功能介绍

Ableton Live 11 Suite mac是一款专业级别的音乐制作软件,它提供了多种音乐制作和编辑功能,可以帮助用户创建各种音乐作品。界面简单直观,可以方便地进行各种音乐制作操作。它提供了丰富的音乐制作工具和功能,如录音、采样、编曲、…

C语言实现模拟 strcmp 字符串比较函数,实现字符串大小的比较

完整代码&#xff1a; // 模拟 strcmp 字符串比较函数&#xff0c;实现字符串大小的比较 #include<stdio.h> //strcmp函数是两个字符串自左向右逐个字符相比&#xff08;按 ASCII 值大小相比较&#xff09;&#xff0c;直到出现不同的字符或遇 \0 为止&#xff0c;如果字…