C语言——单链表实现数据增删查改

一.前言

 嗨嗨嗨,我们又见面了。前面我们已经学习了关于数据结构中的顺序表,今天我们来学习数据结构中的单链表。废话不多说让我们直接开始吧。

二.正文

1.1链表的概念

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

链表的结构跟火车的车厢相似,淡季时车次的车厢会相应减少,旺季时车厢会额外增加几节。只需要将火车里的某节车厢去掉/加上,不会影响其他车厢,每节车厢都是独立存在的。

车厢是独立存在的,且每节车厢都有车门。想象一下这样的场景,假设每节车厢的车门都是锁上的状态,需要不同的钥匙才能解锁,每次只能携带一把钥匙的情况下如何从车头走到车尾?

最简单的做法:每节车厢里都放下一把车厢的钥匙。

在链表里,每节“车厢”是什么样的呢?

与顺序表不同的是,链表里的每节“车厢”都是独立申请下来的空间,我们称之为“节点/结点”

节点的组成主要有两部分:当前节点要保存的数据和保存下一个节点的地址。

图中指针变量plist保存的是第一个节点的地址,我们称plist此时“指向”第一个节点,如果我们希望plist“指向”第二个节点时,只需要修改plist保存的内容为0x0012FFA0。

为什么还需要指针变量来保存下一个节点的位置?

链表中每个节点都是独立申请的(即需要插入数据时采取申请一块节点的空间),我们需要通过指针变量来保存下一个节点位置才能从当前节点找到下一个节点。

1.2单链表的实现

SList.h(用来提前声明函数存在)

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef  int SLTDataType;
typedef struct SListNode//节点的结构由数据data和下一个节点的地址next组成
{SLTDataType data;struct SList* next;
}SLTNode;
void SLTPrint();//打印链表
void SLTPushBack();//尾插
void SLTPushFront();//头插
void SLTPopBack();//尾删
void SLTPopFront();//头删
SLTNode* SLTFind();//查找
void SLTInsertBefore();//在指定位置之前插入数据
void SLTInsertAfter();//在指定位置之后插入数据
void SLTErase();//在指定位置删除节点
void SLTEraseAfter();//在指定位置之后删除节点
void SLTDestroy();//销毁链表

SList.c(用来实现函数功能)

#include"SList.h"
SLTNode* SLTBuyNode(SLTDataType x)//创造节点
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail!");//return;exit(1);}else{newnode->next = NULL;newnode->data = x;return newnode;}
}
void SLTPushBack(SLTNode** pphead,SLTDataType x)//尾插
{assert(pphead);SLTNode* newnode= SLTBuyNode(x);if (*pphead == NULL){*pphead = newnode;}else{//找尾结点SLTNode* ptail = *pphead;while(ptail->next)//疑惑点为什么不是*pphead->next{ptail = ptail->next;}/*	while((*pphead)->next){}*/ptail->next = newnode;}
}
void SLTPrint(SLTNode* phead)//链表打印
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur=pcur->next;}printf("NULL\n");
}
void SLTPushFront(SLTNode** pphead,SLTDataType x)//头插
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}
void SLTPopBack(SLTNode** pphead)//尾删
{assert(pphead && *pphead);if ((*pphead)->next==NULL){free(*pphead);*pphead = NULL;}else{SLTNode* ptail;SLTNode* pcur;ptail = pcur = *pphead;while (ptail->next){pcur = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;pcur->next=NULL;}
}
void SLTPopFront(SLTNode** pphead)//头删
{assert(pphead && *pphead);SLTNode* pcur=*pphead;*pphead = (*pphead)->next;free(pcur);
}
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)//查找
{SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}
void SLTInsertBefore(SLTNode** pphead,SLTNode* pos,SLTDataType x)//在指定位置前插入节点
{assert(pphead && *pphead);assert(pos);SLTNode* newnode = SLTBuyNode( x);//先找到目标位置的前一个节点SLTNode* prev = *pphead;if (pos==*pphead){SLTPopFront(pphead);}else{while (prev->next != pos){prev = prev->next;}newnode->next = pos;prev->next = newnode;}
}
void SLTInsertAfter(SLTNode* pos, SLTDataType x)//在指定位置之后插入节点
{assert(pos);SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}
void SLTErase(SLTNode** pphead,SLTNode* pos)//删除指定位置的节点
{assert(pphead && *pphead);assert(pos);SLTNode* prev = *pphead;if (pos == *pphead){SLTPopFront(pphead);}else{while (prev->next != pos){prev = prev->next;}SLTNode* next = pos->next;prev->next = next;free(pos);pos = NULL;}
}
void SLTEraseAfter(SLTNode* pos)//删除指定位置之后的节点
{assert(pos&&pos->next);SLTNode* next = pos->next;pos->next = next->next;free(next);next = NULL;
}
void SLTDestroy(SLTNode** pphead)//销毁链表
{assert(pphead&&*pphead);SLTNode* next = *pphead;SLTNode* pcur = *pphead;while (pcur){next = (pcur)->next;free(pcur);//	pcur = NULL;pcur = next;//pcur = next;}*pphead = NULL;
}

test.c(用来测试所写代码功能是否正确)

#include"SList.h"
//void test1()//测试尾插和尾删
//{
//	SLTNode* plist = NULL;
//	SLTPushBack(&plist, 1);
//	SLTPushBack(&plist, 2);
//	SLTPushBack(&plist, 3);
//	SLTPushBack(&plist, 4);
//	SLTPopBack(&plist);
//	SLTPrint(plist);
//}
//void test2()//测试头插
//{
//	SLTNode* plist;
//	//plist = NULL;
//	SLTPushFront(&plist, 4);
//	SLTPushFront(&plist, 3);
//	SLTPushFront(&plist, 2);
//	SLTPushFront(&plist, 1);
//	SLTPrint(plist);
//}//void test3()//测试头删
//{
//	SLTNode* plist =NULL;
//	SLTPushBack(&plist, 1);
//	SLTPushBack(&plist, 2);
//	SLTPushBack(&plist, 3);
//	SLTPushBack(&plist, 4);
//	SLTPopFront(&plist);
//	SLTPrint(plist);
//}
//void test4()//测试查找
//{
//	SLTNode* plist = NULL;
//		SLTPushBack(&plist, 1);
//		SLTPushBack(&plist, 2);
//		SLTPushBack(&plist, 3);
//		SLTPushBack(&plist, 4);
//		SLTNode* find = SLTFind(plist, 4);
//}
//void test5()//测试在指定位置前插入节点
//{
//	SLTNode* plist = NULL;
//			SLTPushBack(&plist, 1);
//			SLTPushBack(&plist, 2);
//			SLTPushBack(&plist, 3);
//			SLTPushBack(&plist, 4);
//			SLTNode* find = SLTFind(plist, 3);
//			SLTInsertBefore(&plist, find, 5);
//			SLTPrint(plist);
//}
//void test6()//测试在指定位置之后插入节点
//{
//		SLTNode* plist = NULL;
//			SLTPushBack(&plist, 1);
//			SLTPushBack(&plist, 2);
//			SLTPushBack(&plist, 3);
//			SLTPushBack(&plist, 4);
//			SLTNode* find = SLTFind(plist, 4);
//			SLTInsertAfter(find, 5);
//			SLTPrint(plist);
//}
//test7()//测试在指定位置删除节点
//{
//	SLTNode* plist = NULL;
//	SLTPushBack(&plist, 1);
//	SLTPushBack(&plist, 2);
//	SLTPushBack(&plist, 3);
//	SLTPushBack(&plist, 4);
//	SLTNode* find = SLTFind(plist, 1);
//	SLTErase(&plist, find);
//	SLTPrint(plist);
//}
//void test8()//测试在指定位置之后删除节点
//{
//	SLTNode* plist = NULL;
//	SLTPushBack(&plist, 1);
//	SLTPushBack(&plist, 2);
//	SLTPushBack(&plist, 3);
//	SLTPushBack(&plist, 4);
//	SLTNode* find = SLTFind(plist, 1);
//	SLTEraseAfter(find);
//	SLTPrint(plist);
//}
void test9()//测试销毁链表
{SLTNode* plist = NULL;SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);//SLTPushBack(&plist, 3);//SLTPushBack(&plist, 4);SLTDestroy(&plist);SLTPrint(plist);
}
int main()
{//test1();//test2();//test3();//test4();//test5();//test6();//test7();//test8();test9();return 0;
}

值得注意的是:上面的test.c只是本人在写单链表的时候测试所写函数功能能否跑得起来而所写的,大家也可以按自己的习惯来测试函数功能,上面代码仅供参考。

三.结文

今天的分享就到此结束了,集帅、集美们咱们下期不见不散~

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Flask开发实战】HTML模板代码复用之extends使用

一、前言 在 HTML 开发中&#xff0c;尤其是在使用模板引擎&#xff08;如 Jinja2&#xff0c;常用于 Flask 应用&#xff09;时&#xff0c;extends 是一个非常有用的指令&#xff0c;它用于实现模板继承&#xff0c;从而达到代码复用的目的。这可以让你定义一个基本模板&…

三体中的二向箔

目录 描述 外观 基本原理 攻击范围及影响 副作用 保存方式 实战情况 二向箔是在中国科幻名匠刘慈欣的作品《三体3&#xff1a;死神永生》中登场的宇宙规律武器之一。首次出现于一艘来自歌者“母世界”的宇宙飞船。由于宇宙战争愈演愈烈&#xff0c;二向箔对于高等文明而…

Codigger数据篇(下):数据安全的全方位保障

在数字化浪潮中&#xff0c;数据已成为现代企业的核心财富。Codigger作为领先的数据服务平台&#xff0c;深知数据安全对于用户的重要性&#xff0c;因此在深挖数据价值的同时&#xff0c;我们始终坚守数据安全防线。 一、双重加密技术保障 Codigger平台运用先进的加密通信和…

python 基础语句

python 基础语句 1. import 语句 用于导入相应的包以供后面的代码使用 import xxx -将xxx包导入import pandas as pd - 导入 pandas 包并且将其所有的对象、方法、属性赋予 pd 对象from xxx1 import xxx2 - 从xxx1 包中导入 xxx2 方法 2. 输入输出语句 input&#xff0c;pr…

ip ssl证书无限端口网站

IP SSL证书是由CA认证机构颁发的一种特殊数字证书。大部分SSL数字证书都需要用户使用域名进行申请&#xff0c;想要对公网IP地址加密实现https访问就需要申请IP SSL证书。IP SSL证书采用了强大的加密算法&#xff0c;可以有效地防止数据在传输过程中被窃取或篡改&#xff0c;具…

TS学习-泛型基础

目录 1&#xff0c;介绍1&#xff0c;在函数中使用2&#xff0c;在类型别名&#xff0c;接口中使用3&#xff0c;在类中使用 2&#xff0c;泛型约束3&#xff0c;多泛型4&#xff0c;举例实现 Map 1&#xff0c;介绍 泛型相当于是一个类型变量&#xff0c;有时无法预先知道具体…

药品商品名/通用名/化学名/别名-数据库查询方法

药品通用名-药品化学名-药品商品名的区别 药品通用名通常是由药典委员会或相关药品命名机构根据药品的化学成分或治疗特性制定的标准化名称。这个名称在科学和医疗领域中用于确保对药品的准确和一致性识别。如阿司匹林&#xff08;Aspirin&#xff09;是药品的通用名。&#x…

Tomact安装配置及使用(超详细)

文章目录 web相关知识概述web简介(了解)软件架构模式(掌握)BS&#xff1a;browser server 浏览器服务器CS&#xff1a;client server 客户端服务器 B/S和C/S通信模式特点(重要)web资源(理解)资源分类 URL请求路径(理解)作用介绍格式浏览器通过url访问服务器的过程 服务器(掌握)…

Vue.js课后练习(登录注册和大小比较)

第一题 请编写登录页面和注册页面&#xff0c;通过动态组件实现动态切换页面中显示的组件&#xff0c;效果如图1和图2所示。 图1 登录页面 图2 注册页面 代码&#xff1a; my.vue代码: <template>登录 </template><script setup> </script><st…

maven聚合,继承等方式

需要install安装到本地仓库&#xff0c;或者私服&#xff0c;方可使用自己封装项目 编译&#xff0c;测试&#xff0c;打包&#xff0c;安装&#xff0c;发布 parent: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://mav…

PotatoPie 4.0 实验教程(33) —— FPGA实现摄像头视频图像叠加

链接直达 https://item.taobao.com/item.htm?ftt&id776516984361 什么是视频水印&#xff1f; 视频水印就是图像叠加&#xff0c;跟画中画&#xff0c;或者是OSD是一样的原理&#xff0c;都是在视频的行场数据流上进行替换操作&#xff0c;比如叠加可以直接用水印图的数…

力扣刷题 63.不同路径 II

题干 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到…