数据结构:单链表的实现(C语言)

在这里插入图片描述

个人主页 : 水月梦镜花
个人专栏 : 《C语言》 《数据结构》

文章目录

  • 前言
  • 一、单链表实现思路和图解
    • 1.节点的定义(SListNode)
    • 2.申请一个节点(BuySListNode)
    • 3.单链表打印(SListPrint)
    • 4.单链表尾插(SListPushBack)
    • 5.单链表的头插(SListPushFront)
    • 6.单链表的尾删(SListPopBack)
    • 7.单链表头删(SListPopFront)
    • 8.单链表的查找(SListFind)
    • 9.单链表在pos位置之后插入x(SListInsertAfter)
    • 10.单链表删除在pos位置之后的值(SListEraseAfter)
    • 11.单链表的销毁(SListDestroy)
  • 二、代码实现
  • 总结


前言

本博客将要实现的无头单向不循环链表。


一、单链表实现思路和图解

1.节点的定义(SListNode)

我们将节点定义为如下结构:
在这里插入图片描述
其成员变量有data,next。

将int重命名为STLDataType,方便我们以后修改数据域的内容。

//无头单向不循环链表
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SListNode;

2.申请一个节点(BuySListNode)

动态申明一个空间,来放置数据。如下:
在这里插入图片描述
将data的内容置成形参x,next置NULL。

//申请一个节点
SListNode* BuySListNode(SLTDataType x)
{SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->data = x;newnode->next = NULL;retur

3.单链表打印(SListPrint)

循环遍历链表,直到尾节点。创建一个结构体指针变量cur,循环cur = cur->next,并打印cur->data的内容,直到cur == NULL。
在这里插入图片描述

//单链表打印
void SListPrint(SListNode* plist)
{SListNode* cur = plist;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}

4.单链表尾插(SListPushBack)

  • 如果链表不为NULL(链表中有元素),要先遍历链表找到尾节点,在让尾节点指向新节点,完成尾插。
  • 如果链表为NULL(链表中没有元素),此时应该直接让新节点等于头结点,完成尾插。(本链表是无哨兵位的)
  • 如果传入的头结点无效,直接判错。

在这里插入图片描述

在这里插入图片描述
当链表为NULL,我们就要修改头结点本身的内容,所以我们需要头结点的指针,而本文中头结点本身就是结构体指针,所以尾插函数参数我们需要二级指针。

//单链表尾插
void SListPushBack(SListNode** pplist, SLTDataType x)
{assert(pplist);SListNode* newnode =  BuySListNode(x);if (*pplist != NULL){SListNode* cur = *pplist;while (cur->next != NULL){cur = cur->next;}cur->next = newnode;}else{*pplist = newnode;}
}

5.单链表的头插(SListPushFront)

对于头插而言,链表是否有元素并不重要,我们只需要让新节点的指向头结点,并将头结点等于新节点。

在这里插入图片描述
因为头插链表,一定会改变头结点的内容,所以我们头插函数的形参也是二级指针。

//单链表的头插
void SListPushFront(SListNode** pplist, SLTDataType x)
{assert(pplist);SListNode* newnode = BuySListNode(x);newnode->next = *pplist;*pplist = newnode;
}

6.单链表的尾删(SListPopBack)

  • 如果链表元素有两个及两以上,我们需要两个指针变量prev,next来找尾节点,循环prev = cur,cur = cur->next,使next指向尾节点,prev指向尾节点的前一个,free尾节点,prev指向的节点指向NULL。
  • 如果链表元素只有一个,直接free头结点,使头结点置NULL。
  • 如果链表没有元素,直接判错。

在这里插入图片描述

在这里插入图片描述
当链表元素只有一个时,此时尾删链表,要修改头结点的内容,尾删函数的形参需要二级指针。

//单链表的尾删
void SListPopBack(SListNode** pplist)
{assert(pplist);//链表为NULLassert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{SListNode* cur = *pplist;SListNode* prev = NULL;while (cur->next != NULL){prev = cur;cur = cur->next;}prev->next = NULL;free(cur);}
}

7.单链表头删(SListPopFront)

我们需要一个结构体指针变量next,来保存头结点的下一个节点,然后free头结点,使头结点 = 指针变量next。

  • 如果链表没有元素,直接判错。

在这里插入图片描述

//单链表头删
void SListPopFront(SListNode** pplist)
{assert(pplist);assert(*pplist);SListNode* next = (*pplist)->next;free(*pplist);*pplist = next;
}

8.单链表的查找(SListFind)

我们需要一个结构体指针变量cur,来遍历链表比较cur->data == x,如果相等,放回此时cur的内容(该节点的地址)。如果遍历完链表,并没有相等元素,放回NULL。

//单链表的查找
SListNode* SListFind(SListNode* plist, SLTDataType x)
{SListNode* cur = plist;while (cur != NULL){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

9.单链表在pos位置之后插入x(SListInsertAfter)

我们让newnode指向pos下一个的节点,pos指向newnode。

  • 如果我们先让pos指向newnode,newnode在指向pos的下一个节点,就会造成newnode指向自己,导致链表成环。
  • 该函数不会影响头结点的内容,所以函数的形参不用二级指针。

在这里插入图片描述


//单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDataType x)
{assert(pos);SListNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;
}

10.单链表删除在pos位置之后的值(SListEraseAfter)

我们需要一个结构体指针变量next,记录pos下一个节点的地址,然后是pos指向next的下一个节点,接着free(next)。

  • 如果链表只有一个元素,我们不能调用该函数,否则会导致NULL指针的解引用。
  • 该函数不会改变头结点的内容,所以形参我们不用二级指针。

在这里插入图片描述


//单链表删除在pos位置之后的值
void SListEraseAfter(SListNode* pos)
{assert(pos && pos->next);SListNode* next = pos->next;pos->next = next->next;free(next);
}

11.单链表的销毁(SListDestroy)

我们需要两个结构体指针prev,cur。先让prev = cur ,cur再指向下一个节点,free(prev),重复上述操作,直到cur指向NULL。

在这里插入图片描述
需要我们在函数调用完后,自己对头结点置NULL。

//单链表的销毁
void SListDestroy(SListNode* plist)
{assert(plist);SListNode* cur = plist;while (cur != NULL){SListNode* prev = cur;cur = cur->next;free(prev);}
}

二、代码实现

//slist.h  文件#pragma once
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>
#include <stdlib.h>
#include <assert.h>//无头单向不循环链表
typedef int SLTDataType;typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SListNode;//申请一个节点
SListNode* BuySListNode(SLTDataType x);//单链表打印
void SListPrint(SListNode* plist);//单链表尾插
void SListPushBack(SListNode** pplist, SLTDataType x);//单链表的头插
void SListPushFront(SListNode** pplist, SLTDataType x);//单链表的尾删
void SListPopBack(SListNode** pplist);//单链表头删
void SListPopFront(SListNode** pplist);//单链表的查找
SListNode* SListFind(SListNode* plist, SLTDataType x);//单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDataType x);//单链表删除在pos位置之后的值
void SListEraseAfter(SListNode* pos);//单链表的销毁
void SListDestroy(SListNode* plist);
//slist.c    文件#include "slist.h"//申请一个节点
SListNode* BuySListNode(SLTDataType x)
{SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc");exit(-1);}newnode->data = x;newnode->next = NULL;return newnode;
}//单链表打印
void SListPrint(SListNode* plist)
{SListNode* cur = plist;while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}//单链表尾插
void SListPushBack(SListNode** pplist, SLTDataType x)
{assert(pplist);SListNode* newnode =  BuySListNode(x);if (*pplist != NULL){SListNode* cur = *pplist;while (cur->next != NULL){cur = cur->next;}cur->next = newnode;}else{*pplist = newnode;}
}//单链表的头插
void SListPushFront(SListNode** pplist, SLTDataType x)
{assert(pplist);SListNode* newnode = BuySListNode(x);newnode->next = *pplist;*pplist = newnode;
}//单链表的尾删
void SListPopBack(SListNode** pplist)
{assert(pplist);//链表为NULLassert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{SListNode* cur = *pplist;SListNode* prev = NULL;while (cur->next != NULL){prev = cur;cur = cur->next;}prev->next = NULL;free(cur);}
}//单链表头删
void SListPopFront(SListNode** pplist)
{assert(pplist);assert(*pplist);SListNode* next = (*pplist)->next;free(*pplist);*pplist = next;
}//单链表的查找
SListNode* SListFind(SListNode* plist, SLTDataType x)
{SListNode* cur = plist;while (cur != NULL){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}//单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDataType x)
{assert(pos);SListNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;
}//单链表删除在pos位置之后的值
void SListEraseAfter(SListNode* pos)
{assert(pos && pos->next);SListNode* next = pos->next;pos->next = next->next;free(next);
}//单链表的销毁
void SListDestroy(SListNode* plist)
{assert(plist);SListNode* cur = plist;while (cur != NULL){SListNode* prev = cur;cur = cur->next;free(prev);}
}

总结

以上就是我对于无头单向不循环链表的实现!!!

在这里插入图片描述

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

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

相关文章

【目标检测】基于yolov5的水下垃圾检测(附代码和数据集,7684张图片)

写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬步以至千里,就…

行云管家荣获CFS第十二届财经峰会 “2023产品科技创新奖”

7月26日至27日&#xff0c;CFS第十二届财经峰会暨2023可持续商业大会在京盛大召开。峰会主题为“激活高质量发展澎湃活力”&#xff0c;超1000位政商领袖、专家学者、企业及媒体代表出席了本次盛会&#xff0c;共同分享新技术新产品新趋势、研判全球新挑战与新变局下企业的机遇…

【方法】PDF可以转换成Word文档吗?如何操作?

很多人喜欢在工作中使用PDF&#xff0c;因为PDF格式可以准确地保留文档的原始格式&#xff0c;比如字体、图像、布局和颜色等。 但如果编辑文档的话&#xff0c;PDF还是没有Word文档方便。那可以将PDF转换成Word格式&#xff0c;再来编辑吗&#xff1f;如何操作呢&#xff1f;…

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(13)-Fiddler请求和响应断点调试

1.简介 Fiddler有个强大的功能&#xff0c;可以修改发送到服务器的数据包&#xff0c;但是修改前需要拦截&#xff0c;即设置断点。设置断点后&#xff0c;开始拦截接下来所有网页&#xff0c;直到取消断点。这个功能可以在数据包发送之前&#xff0c;修改请求参数&#xff1b…

JVM复习(史上最全!!!)

一、JDK、JRE、JVM的区别 JDK: 全称Java Development Kit&#xff0c;是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的Java应用程序。JDK是整个Java开发的核心。 JRE: JRE&#xff0c;全称Java Runtime Environment&#xff0c;是指Java的运行环境&…

开放麒麟1.0发布一个月后,到底怎么样?另一款操作系统引发热议

具有里程碑意义 7月5日&#xff0c;国产首个开源桌面操作系统“开放麒麟1.0”正式发布。 标志着我国拥有了操作系统组件自主选型、操作系统独立构建的能力&#xff0c;填补了我国在这一领域的空白。 举国欢庆&#xff0c;算的上是里程碑意义了&#xff01; 发布后用着如何&a…

【业务功能篇57】Springboot + Spring Security 权限管理 【上篇】

4.权限管理模块开发 4.1 权限管理概述 4.1.1 权限管理的意义 后台管理系统中&#xff0c;通常需要控制不同的登录用户可以操作的内容。权限管理用于管理系统资源&#xff0c;分配用户菜单、资源权限&#xff0c;以及验证用户是否有访问资源权限。 4.1.2 RBAC权限设计模型 …

redis的并发安全问题:redis的事务VSLua脚本

redis为什么会发生并发安全问题&#xff1f; 在redis中&#xff0c;处理的数据都在内存中&#xff0c;数据操作效率极高&#xff0c;单线程的情况下&#xff0c;qps轻松破10w。反而在使用多线程时&#xff0c;为了保证线程安全&#xff0c;采用了一些同步机制&#xff0c;以及多…

windows中注册redis服务启动时报1067错误

注册完redis服务&#xff0c;打开计算机 服务时确实有redis服务存在&#xff0c;但是点击启动时却报1067错误&#xff0c;而命令行用redis-server.exe redis.windows.conf 命令却也可以启动 查看6379的端口也没有被占用&#xff08;netstat -ano | findstr :6379&#xff09; …

Mac 定时重启 TouchBar 脚本(缓解闪烁问题)

背景 Mac 笔记本 TouchBar 是真的脆啊&#xff0c;合盖使用一段时间就废了&#xff0c;右侧一直闪烁简直亮瞎眼 &#x1f602; 经过观察&#xff0c;总结出闪烁规律如下&#xff1a; 工作状态&#xff1a;不断操作电脑时&#xff0c;触控栏处于工作状态&#xff0c;几乎不闪…

Apipost教程?一篇文章玩转Apipost

你是否经常遇到接口开发过程中的各种问题&#xff1f;或许你曾为接口测试与调试的繁琐流程而烦恼。不要担心&#xff01;今天我将向大家介绍一款功能强大、易于上手的接口测试工具——Apipost&#xff0c;并带你深入了解如何玩转它&#xff0c;轻松实现接口测试与调试。 什么是…

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程(无缺失)

1992-2021年全国及31省对外开放度测算数据含原始数据和计算过程&#xff08;无缺失&#xff09; 1、时间&#xff1a;1992-2021年 2、范围&#xff1a;全国及31省 3、指标&#xff1a;进出口总额、国内生产总值、年均汇率 4、计算方法&#xff1a;对外开放度进出口总额/GDP…

【Linux 网络】 HTTPS协议原理 对称加密 非对称加密 数字证书

HTTPS协议 HTTPS协议和HTTP协议的区别什么是“加密” 和“解密”加密和解密的小故事 为什么要进行加密&#xff1f;臭名昭著的“运营商劫持”事件 常见加密方式对称加密非对称加密 数据摘要数字签名 HTTPS工作过程探究方案 1 &#xff1a; 只使用对称加密方案2 &#xff1a; 只…

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】

从0到1开发go-tcp框架【2-实现Message模块、解决TCP粘包问题、实现多路由机制】 1 实现\封装Message模块 zinx/ziface/imessage.go package zifacetype IMessage interface {GetMsdId() uint32GetMsgLen() uint32GetMsgData() []byteSetMsgId(uint32)SetData([]byte)SetData…

淘宝10年架构演进

目录 1. 概述 2. 基本概念 3. 架构演进 3.1 单机架构 3.2 第一次演进&#xff1a;Tomcat与数据库分开部署 3.3 第二次演进&#xff1a;引入本地缓存和分布式缓存 3.4 第三次演进&#xff1a;引入反向代理实现负载均衡 3.5 第四次演进&#xff1a;数据库读写分离 3.6 第…

C语言第十三课--------初阶指针的认识--------重要部分

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; &#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382;…

CTF:信息泄露.(CTFHub靶场环境)

CTF&#xff1a;信息泄露.&#xff08;CTFHub靶场环境&#xff09; “ 信息泄露 ” 是指网站无意间向用户泄露敏感信息&#xff0c;泄露了有关于其他用户的数据&#xff0c;例如&#xff1a;另一个用户名的财务信息&#xff0c;敏感的商业 或 商业数据 &#xff0c;还有一些有…

无涯教程-jQuery - Ajax Tutorial函数

AJAX是用于创建交互式Web应用程序的Web开发技术。如果您了解JavaScript,HTML,CSS和XML,则只需花费一个小时即可开始使用AJAX。 为什么要学习Ajax? AJAX代表 A 同步 Ja vaScript和 X ML。 AJAX是一项新技术,可借助XML,HTML,CSS和Java Script创建更好,更快,更具交互性的Web应用…

QT数据库编程

ui界面 mainwindow.cpp #include "mainwindow.h" #include "ui_mainwindow.h" #include <QButtonGroup> #include <QFileDialog> #include <QMessageBox> MainWindow::MainWindow(QWidget* parent): QMainWindow(parent), ui(new Ui::M…