当前位置: 首页 > news >正文

无头+单向+非循环链表的实现

这里写目录标题

  • 1. 链表
    • 1.1 链表的概念及结构
    • 1.2 链表的分类
  • 2. 接口实现
  • 3. 链表的实现
    • 3.1 打印链表
    • 3.2 头插
    • 3.3 尾插
    • 3.4 头删
    • 3.5 尾删
    • 3.6 单链表查找
    • 3.7 在pos之前插入
    • 3.8 在pos之后插入
    • 3.9 删除pos位置的值
    • 3.10 删除pos位置之后的值
    • 3.11 链表的释放
    • 3.12 动态申请一个节点
  • 4. 链表的测试
    • 4.1 尾插测试
    • 4.2 空链表头插
    • 4.3 尾删测试
    • 4.4 查找修改测试
    • 4.5 pos前插和后插以及删除pos位置的值
  • 5. 整体代码
    • 5.1 test.c 文件
    • 5.2 SList.h 文件
    • 5.3 SList.c 文件

1. 链表

1.1 链表的概念及结构

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2 链表的分类

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:
在这里插入图片描述

在这里插入图片描述

  1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。

2. 接口实现

接口就是函数定义

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;//数据域struct SListNode* next;//指针域
}SLTNode;//打印链表
void SLTPrint(SLTNode* phead);//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x);//头删
void SLPopFront(SLTNode** pphead);//尾删
void SLPopBack(SLTNode** pphead);//单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x);//在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos);//删除pos位置之后的值
void SLEraseAfter(SLTNode* pos);//链表的释放
void SLDestroy(SLTNode** pphead);

3. 链表的实现

3.1 打印链表

//打印链表
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;//找结构体下一个指针,循环才能走起来}printf("NULL\n");
}

3.2 头插

//头插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址//assert(*pphead);//不能断言,链表为空,也需要插入SLTNode* newnode = BuyLTNode(x);newnode->next = *pphead;*pphead = newnode;
}

3.3 尾插

//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址//assert(*pphead);//链表为空,可以插入SLTNode* newnode = BuyLTNode(x);//空链表if (*pphead == NULL){*pphead = newnode;}//非空链表else{SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}SLTNode* newnode = BuyLTNode(x);tail->next = newnode;}}

3.4 头删

//头删
void SLPopFront(SLTNode** pphead)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址assert(*pphead);//空链表,不能头删一个节点//if (((*pphead)->next) == NULL)//{//	free(*pphead);//	*pphead = NULL;//}多个节点//else//{//	SLTNode* head = *pphead;//	*pphead = head->next;//	free(head);//}SLTNode* del = *pphead;*pphead = del->next;free(del);
}

3.5 尾删

//尾删
void SLPopBack(SLTNode** pphead)
{//没有节点(空链表)//暴力检查assert(*pphead);//一个节点if (((*pphead)->next) == NULL){free(*pphead);*pphead = NULL;}else{//多个节点SLTNode* tail = *pphead;//找尾while (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}
}

3.6 单链表查找

//单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

3.7 在pos之前插入

//在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);if (*pphead == pos){SLPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuyLTNode(x);prev->next = newnode;newnode->next = pos;}
}

3.8 在pos之后插入

//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{SLTNode* newnode = BuyLTNode(x);newnode->next = pos->next;pos->next = newnode;
}

3.9 删除pos位置的值

//删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);if (*pphead == pos){SLPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}

3.10 删除pos位置之后的值

//删除pos位置之后的值
void SLEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* next = pos->next;pos->next = next->next;free(next);
}

3.11 链表的释放

//链表的释放
void SLDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* next = cur->next;free(cur);cur = next;}*pphead = NULL;
}

3.12 动态申请一个节点

//动态开辟一个newnode结构体,不free不释放
SLTNode* BuyLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("BuyLTNode");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}

4. 链表的测试

4.1 尾插测试

//尾插测试
void TestSLish1()
{SLTNode* plist = NULL;SLPushFront(&plist, 1);SLPushFront(&plist, 2);SLPushFront(&plist, 3);SLPushFront(&plist, 4);SLTPrint(plist);SLPushBack(&plist, 5);SLTPrint(plist);
}int main()
{TestSLish1();return 0;
}

运行演示:
在这里插入图片描述

4.2 空链表头插

//空链表头插
void TestSLish2()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);
}int main()
{TestSLish2();return 0;
}

运行演示:
在这里插入图片描述

4.3 尾删测试

//尾删测试
void TestSLish3()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPopBack(&plist);SLTPrint(plist);SLPopBack(&plist);SLTPrint(plist);SLPopBack(&plist);SLTPrint(plist);
}int main()
{TestSLish3();return 0;
}

运行演示:
在这里插入图片描述

4.4 查找修改测试

//查找修改测试
void TestSLish4()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);SLTNode* pos = STFind(plist, 3);if (pos)pos->data = 30;SLTPrint(plist);
}int main()
{TestSLish4();return 0;
}

运行演示:
在这里插入图片描述

4.5 pos前插和后插以及删除pos位置的值

//pos前插和后插,测试
//删除pos位置的值
void TestSLish5()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);SLTNode* pos = STFind(plist, 3);if (pos){SLInsert(&plist, pos, 30);}SLTPrint(plist);pos = STFind(plist, 2);if (pos){SLInsertAfter(pos, 20);}SLTPrint(plist);pos = STFind(plist, 2);if (pos){SLErase(&plist, pos);}SLTPrint(plist);SLDestroy(&plist);
}int main()
{TestSLish5();return 0;
}

运行演示:
在这里插入图片描述

5. 整体代码

5.1 test.c 文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"//尾插测试
void TestSLish1()
{SLTNode* plist = NULL;SLPushFront(&plist, 1);SLPushFront(&plist, 2);SLPushFront(&plist, 3);SLPushFront(&plist, 4);SLTPrint(plist);SLPushBack(&plist, 5);SLTPrint(plist);
}//空链表头插
void TestSLish2()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);
}//尾删测试
void TestSLish3()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPopBack(&plist);SLTPrint(plist);SLPopBack(&plist);SLTPrint(plist);SLPopBack(&plist);SLTPrint(plist);
}//查找修改测试
void TestSLish4()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);SLTNode* pos = STFind(plist, 3);if (pos)pos->data = 30;SLTPrint(plist);
}//pos前插和后插,测试
//删除pos位置的值
void TestSLish5()
{SLTNode* plist = NULL;SLPushBack(&plist, 1);SLPushBack(&plist, 2);SLPushBack(&plist, 3);SLPushBack(&plist, 4);SLPushBack(&plist, 5);SLTPrint(plist);SLTNode* pos = STFind(plist, 3);if (pos){SLInsert(&plist, pos, 30);}SLTPrint(plist);pos = STFind(plist, 2);if (pos){SLInsertAfter(pos, 20);}SLTPrint(plist);pos = STFind(plist, 2);if (pos){SLErase(&plist, pos);}SLTPrint(plist);SLDestroy(&plist);
}int main()
{TestSLish1();return 0;
}

5.2 SList.h 文件

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int SLTDataType;
typedef struct SListNode
{SLTDataType data;//数据域struct SListNode* next;//指针域
}SLTNode;//打印链表
void SLTPrint(SLTNode* phead);//头插
void SLPushFront(SLTNode** pphead, SLTDataType x);//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x);//头删
void SLPopFront(SLTNode** pphead);//尾删
void SLPopBack(SLTNode** pphead);//单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x);//在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos);//删除pos位置之后的值
void SLEraseAfter(SLTNode* pos);//链表的释放
void SLDestroy(SLTNode** pphead);

5.3 SList.c 文件

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"//打印链表
void SLTPrint(SLTNode* phead)
{SLTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;//找结构体下一个指针,循环才能走起来}printf("NULL\n");
}//动态开辟一个newnode结构体,不free不释放
SLTNode* BuyLTNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("BuyLTNode");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}//头插
void SLPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址//assert(*pphead);//不能断言,链表为空,也需要插入SLTNode* newnode = BuyLTNode(x);newnode->next = *pphead;*pphead = newnode;
}//尾插
void SLPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址//assert(*pphead);//链表为空,可以插入SLTNode* newnode = BuyLTNode(x);//空链表if (*pphead == NULL){*pphead = newnode;}//非空链表else{SLTNode* tail = *pphead;while (tail->next != NULL){tail = tail->next;}SLTNode* newnode = BuyLTNode(x);tail->next = newnode;}}//头删
void SLPopFront(SLTNode** pphead)
{assert(pphead);//链表为空,pphead也不为空,因为它是头指针plist的地址assert(*pphead);//空链表,不能头删一个节点//if (((*pphead)->next) == NULL)//{//	free(*pphead);//	*pphead = NULL;//}多个节点//else//{//	SLTNode* head = *pphead;//	*pphead = head->next;//	free(head);//}SLTNode* del = *pphead;*pphead = del->next;free(del);
}//尾删
void SLPopBack(SLTNode** pphead)
{//没有节点(空链表)//暴力检查assert(*pphead);//一个节点if (((*pphead)->next) == NULL){free(*pphead);*pphead = NULL;}else{//多个节点SLTNode* tail = *pphead;//找尾while (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}
}//单链表查找
SLTNode* STFind(SLTNode* phead, SLTDataType x)
{SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}//在pos之前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);if (*pphead == pos){SLPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}SLTNode* newnode = BuyLTNode(x);prev->next = newnode;newnode->next = pos;}
}//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{SLTNode* newnode = BuyLTNode(x);newnode->next = pos->next;pos->next = newnode;
}//删除pos位置的值
void SLErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(pos);if (*pphead == pos){SLPopFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);}
}//删除pos位置之后的值
void SLEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* next = pos->next;pos->next = next->next;free(next);
}//链表的释放
void SLDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* cur = *pphead;while (cur){SLTNode* next = cur->next;free(cur);cur = next;}*pphead = NULL;
}

相关文章:

  • web学习笔记(六十五)
  • Recognize Anything: A Strong Image Tagging Model(RAM模型使用方法)
  • 各品牌电视安装第三方软件失败的解决方法
  • 理解数仓建模
  • 移动安全赋能化工能源行业智慧转型
  • 软件2_算法功能23
  • 数据库(28)——联合查询
  • Web前端Hack:深入探索、挑战与防范
  • 【C++】深入理解decltype和decltype(auto)
  • MyBatisPlus插件生成代码
  • Web前端 CodeView:深度解析与实用指南
  • .net后端程序发布到nignx上,通过nginx访问
  • 【React】json-server
  • 【第13章】SpringBoot实战篇之项目部署
  • 医疗器械网络安全风险管理的基本步骤
  • python3.6+scrapy+mysql 爬虫实战
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 30秒的PHP代码片段(1)数组 - Array
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • ERLANG 网工修炼笔记 ---- UDP
  • es6
  • Fastjson的基本使用方法大全
  • JavaScript DOM 10 - 滚动
  • jquery cookie
  • js继承的实现方法
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 编写符合Python风格的对象
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 算法-图和图算法
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 如何用纯 CSS 创作一个货车 loader
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​TypeScript都不会用,也敢说会前端?
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • # Kafka_深入探秘者(2):kafka 生产者
  • # 透过事物看本质的能力怎么培养?
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (C语言)逆序输出字符串
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (利用IDEA+Maven)定制属于自己的jar包
  • (篇九)MySQL常用内置函数
  • (四)React组件、useState、组件样式
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (轉貼) UML中文FAQ (OO) (UML)
  • .htaccess配置常用技巧
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net FrameWork简介,数组,枚举
  • .Net FrameWork总结
  • .NET与 java通用的3DES加密解密方法
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • .pop ----remove 删除
  • @configuration注解_2w字长文给你讲透了配置类为什么要添加 @Configuration注解