数据结构--单链表(图文)

单链表的概念

在单链表中,每个元素(称为节点)包含两部分:一部分是存储数据的数据域,另一部分是存储下一个节点地址的指针域。这里的“单”指的是每个节点只有一个指向下一个节点的指针。
在这里插入图片描述

  1. 节点:链表中的基本单元,通常由数据域和指针域组成。数据域用于存储实际的数据,而指针域用于指向链表中的下一个节点。

  2. :通过节点中的指针链接形成的序列。在单链表中,这种链接是单向的,即只能从一个节点指向下一个节点。

  3. 头节点:链表的第一个节点,用于标识链表的开始。有时,头节点仅作为链表的头部标识,不存储实际数据。

  4. 尾节点:链表的最后一个节点,其指针域通常为空(NULL),表示链表的结束。

  5. 非连续性:与数组不同,单链表的节点在内存中不必连续存储。每个节点的位置由其前一个节点的指针决定。

  6. 动态性:单链表的大小是动态的,可以在运行时通过增加或删除节点来改变链表的长度。

单链表的主要特点是其灵活性和动态性,它可以有效地进行插入和删除操作,尤其是在不知道数据数量的情况下,或者当数据量变化较大时。但是,由于需要通过指针进行遍历,单链表在访问特定元素时可能不如数组高效。以下是其在各种操作中的优势:

  • 插入和删除:在单链表中插入或删除节点只需要O(1)的时间,前提是已经有了指向要操作节点的指针。
  • 空间利用:单链表不需要预分配固定的存储空间,它可以根据需要动态地分配内存。

单链表的实现

首先创建三个文件:

  • SList.h —— 用于声明函数的头文件
  • SList.c —— 单链表主要函数的实现
  • test.c——测试单链表。

创建单链表

typedef int SLTDataType;//方便后续使用更改类型//创建一个节点
typedef struct SListNode
{SLTDataType data;//该节点储存的数据struct SListNode* next;//指向下一个节点的指针
}SListNode;

销毁链表

从前向后依次释放节点,最后将头节点置为NULL 。

void SListDesTroy(SListNode** pphead)//销毁链表
{assert(pphead && *pphead);SListNode* pcur = *pphead;while (pcur){SListNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

打印节点数据

遍历依次打印即可。

void SLTPrint(SListNode* phead)//打印节点数据
{assert(phead);SListNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

申请一块节点

在进行插入节点时,我们需要先申请一块节点来进行插入,所以我们将申请节点单独封装成一个函数。

SListNode* SLTBuyNode(SLTDataType x)//增加节点(空间)
{//开辟一个节点空间SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc");exit(1);}//设置数据并返回该节点地址newnode->data = x;newnode->next = NULL;return newnode;
}

尾插数据

两种情况

  • 情况一:链表为空直接申请新节点给头节点;
  • 情况二:链表不为空,遍历找到尾节点,再将新节点接入即可。

在这里插入图片描述

void SLTPushBack(SListNode** pphead, SLTDataType x)//尾插数据
{assert(pphead);//不能为空,否则就会对空指针解引用if (*pphead == NULL)//指向头节点的指针为空,也就是链表为空{*pphead = SLTBuyNode(x);}else{SListNode* newnode = *pphead;while (newnode->next){newnode = newnode->next;}newnode->next = SLTBuyNode(x);}
}

头插数据

两种情况

  • 情况一:链表为空直接申请新节点给头节点。
  • 情况二:链表不为空,先将pphead(头节点)保存起来,然后让pphead指向新插入的节点,在让*pphead->next指向刚才保存好的原本的头节点。
    在这里插入图片描述
void SLTPushFront(SListNode** pphead, SLTDataType x)//头插数据
{assert(pphead);if (*pphead == NULL){*pphead = SLTBuyNode(x);}else{SListNode* pcur = *pphead;*pphead = SLTBuyNode(x);(*pphead)->next = pcur;}
}

尾删数据

两种情况

  • 情况一:链表只有一个数据,直接释放该节点并将头节点置为空。
  • 情况二:链表有多个数据节点,遍历找到尾节点的前一个节点,释放该节点的next节点,再将该节点的next置为空。
    在这里插入图片描述
void SLTPopBack(SListNode** pphead)//尾删数据
{assert(pphead && *pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SListNode* pcur = *pphead;while (pcur->next->next){pcur = pcur->next;}free(pcur->next);pcur->next = NULL;}
}

头删数据

两种情况

  • 情况一:链表只有一个数据,直接释放该节点并将头节点置为空。
  • 情况二:链表有多个数据节点,先将pphead(头节点)保存起来,然后让pphead指向*pphead->next(新的头节点),然后释放刚才保存的节点(原头节点)。
    在这里插入图片描述
void SLTPopFront(SListNode** pphead)//头删数据
{assert(pphead && *pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SListNode* pcur = (*pphead);*pphead = (*pphead)->next;free(pcur);}
}

查找数据

从前向后遍历整个链表,如果 plist->data == x,就说明找到了,返回 plist 此时的值,如果plist = NULL了,就说明这个链表中没有该数据,则返回空。

SListNode* SLTFind(SListNode* phead, SLTDataType x)//查找数据
{assert(phead);SListNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}

有了查找函数,就可以实现任意位置的增加数据和删除数据的操作了。

在指定位置之前插入数据

两种情况

  • 情况一:指定位置为头节点则直接头插。
  • 情况二:指定位置为其他节点,遍历找到指定节点的前一个节点,在该节点后插入新数据。
    在这里插入图片描述
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x)//在指定位置之前插入数据
{assert(pphead&&*pphead);if (*pphead == pos){SLTPushFront(pphead,x);}else{SListNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}SListNode* newnode = SLTBuyNode(x);pcur->next = newnode;newnode->next = pos;}
}

在指定位置之后插入数据

在指定位置后直接插入即可。

void SLTInsertAfter(SListNode* pos, SLTDataType x)//在指定位置之后插入数据
{assert(pos);SListNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}

删除指定位置节点

两种情况

  • 情况一:指定位置为头节点则直接头删。
  • 情况二:指定位置为其他节点,遍历找到指定位置的前一个节点,先将该节点的next指针指向指定位置的next位置,然后再释放指定位置。(不能改变顺序,否则找不到指定位置的下一个节点了)
    在这里插入图片描述
void SLTErase(SListNode** pphead, SListNode* pos)//删除pos节点
{assert(*pphead && pphead);assert(pos);if (*pphead == pos){SLTPopFront(pphead);}else{SListNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}

删除指定位置之后的数据

先将指定位置的的下一个位置保存起来,让指定位置的next指针指向保存位置的下一个位置,然后释放掉保存的位置也就是指定位置之后的数据。
在这里插入图片描述

void SLTEraseAfter(SListNode* pos)//删除pos之后的节点
{assert(pos && pos->next);SListNode* pcur = pos->next;pos->next = pos->next->next;free(pcur);pcur = NULL;	
}

单链表源码

SList.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>typedef int SLTDataType;//创建一个节点
typedef struct SListNode
{SLTDataType data;struct SListNode* next;
}SListNode;SListNode* SLTBuyNode(SLTDataType x);//增加节点(空间)void SLTPrint(SListNode* phead);//打印节点数据void SListDesTroy(SListNode** pphead);//销毁链表void SLTPushBack(SListNode** pphead, SLTDataType x);//尾插数据void SLTPushFront(SListNode** pphead, SLTDataType x);//头插数据SListNode* SLTFind(SListNode* phead, SLTDataType x) ;//查找数据void SLTPopBack(SListNode** pphead);//尾删数据void SLTPopFront(SListNode** pphead);//头删数据void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x);//在指定位置之前插入数据void SLTInsertAfter(SListNode* pos, SLTDataType x);//在指定位置之后插入数据void SLTErase(SListNode** pphead, SListNode* pos);//删除pos节点void SLTEraseAfter(SListNode* pos);//删除pos之后的节点

SList.c

#include"SList.h"SListNode* SLTBuyNode(SLTDataType x)//增加节点(空间)
{//开辟一个节点空间SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc");exit(1);}//设置数据并返回该节点地址newnode->data = x;newnode->next = NULL;return newnode;
}
void SLTPrint(SListNode* phead)//打印节点数据
{assert(phead);SListNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}
void SListDesTroy(SListNode** pphead)//销毁链表
{assert(pphead && *pphead);SListNode* pcur = *pphead;while (pcur){SListNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}void SLTPushBack(SListNode** pphead, SLTDataType x)//尾插数据
{assert(pphead);if (*pphead == NULL){*pphead = SLTBuyNode(x);}else{SListNode* newnode = *pphead;while (newnode->next){newnode = newnode->next;}newnode->next = SLTBuyNode(x);}
}void SLTPushFront(SListNode** pphead, SLTDataType x)//头插数据
{assert(pphead);if (*pphead == NULL){*pphead = SLTBuyNode(x);}else{SListNode* pcur = *pphead;*pphead = SLTBuyNode(x);(*pphead)->next = pcur;}
}SListNode* SLTFind(SListNode* phead, SLTDataType x)//查找数据
{assert(phead);SListNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}void SLTPopBack(SListNode** pphead)//尾删数据
{assert(pphead && *pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SListNode* pcur = *pphead;while (pcur->next->next){pcur = pcur->next;}free(pcur->next);pcur->next = NULL;}
}void SLTPopFront(SListNode** pphead)//头删数据
{assert(pphead && *pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SListNode* pcur = (*pphead);*pphead = (*pphead)->next;free(pcur);}
}void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x)//在指定位置之前插入数据
{assert(pphead&&*pphead);if (*pphead == pos){SLTPushFront(pphead,x);}else{SListNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}SListNode* newnode = SLTBuyNode(x);pcur->next = newnode;newnode->next = pos;}
}void SLTInsertAfter(SListNode* pos, SLTDataType x)//在指定位置之后插入数据
{assert(pos);SListNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;
}void SLTErase(SListNode** pphead, SListNode* pos)//删除pos节点
{assert(*pphead && pphead);assert(pos);if (*pphead == pos){SLTPopFront(pphead);}else{SListNode* pcur = *pphead;while (pcur->next != pos){pcur = pcur->next;}pcur->next = pos->next;free(pos);pos = NULL;}
}void SLTEraseAfter(SListNode* pos)//删除pos之后的节点
{assert(pos && pos->next);SListNode* pcur = pos->next;pos->next = pos->next->next;free(pcur);pcur = NULL;	
}

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

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

相关文章

Apple - Secure Coding Guide

本文翻译整理自&#xff1a;Secure Coding Guide https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Introduction.html#//apple_ref/doc/uid/TP40002477-SW1 文章目录 一、安全编码指南简介1、概览黑客和攻击者没有平台是免疫…

【办公类-50-01】20240620自主游戏观察记录表19周内容打乱

背景需求&#xff1a; 又到了期末&#xff0c;各种班级资料需要提交。 有一份自主游戏观察记录需要写19周&#xff08;每周2次&#xff09;的观察记录&#xff0c;并根据参考书填写一级、三级、五级的评价指标。 去年中六班的时候&#xff0c;我很认真的手写了21周的户外游戏…

具有 Hudi、MinIO 和 HMS 的现代数据湖

Apache Hudi 已成为管理现代数据湖的领先开放表格式之一&#xff0c;直接在现代数据湖中提供核心仓库和数据库功能。这在很大程度上要归功于 Hudi 提供了表、事务、更新/删除、高级索引、流式摄取服务、数据聚类/压缩优化和并发控制等高级功能。 我们已经探讨了 MinIO 和 Hudi…

Vue3 - 在项目中使用vue-i18n不生效的问题

检查和配置 Vue I18n 确保你已经正确安装了Vue I18n并且配置了组合API模式。 安装 Vue I18n npm install vue-i18nnext配置 i18n.js import { createI18n } from vue-i18n; import messages from ./messages;const i18n createI18n({legacy: false, // 使用组合 API 模式l…

Linux检查端口nmap

yum install -y nmap # 查看本机在运行的服务的端口号 nmap 127.0.0.1 补充&#xff1a;netstat netstat -tunlp | grep 3306

读《文明之光》第2册总结

《文明之光》系列大致按照从地球诞生到近现代的顺序讲述了人类文明进程的各个阶段&#xff0c;每个章节相对独立&#xff0c;全景式地展现了人类文明发展历程中的多样性。《文明之光》系列第二册讲述了从近代科学兴起&#xff0c;到工业革命时代&#xff0c;以及原子能应用这一…

C++/Qt 小知识记录7

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识7 编译FFMPEG遇到的问题CMakeLists.txt配置FFMPEG的依赖方式&#xff1a; x264在Windows下编译生成*.libVS编译Qt工程时&#xff0c;遇到提示Change Qt Version的情况在QtOsg的窗口上嵌入子窗口&…

基于JSP的交通事故档案管理系统

开头语&#xff1a;你好&#xff0c;我是计算机学长猫哥&#xff0c;如果你对系统有更多的期待或建议&#xff0c;欢迎随时联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSPJava 工具&#xff1a;ECLIPSE、Tomcat 系统展示 首页 管理员界…

车辆数据的提取、定位和融合(其一 共十二篇)

第一篇&#xff1a; System Introduction 第二篇&#xff1a;State of the Art 第三篇&#xff1a;localization 第四篇&#xff1a;Submapping and temporal weighting 第五篇&#xff1a;Mapping of Point-shaped landmark data 第六篇&#xff1a;Clustering of landma…

Dockerfile实战

Dockerfile是用来快速创建自定义镜像的一种文本格式的配置文件&#xff0c;在持续集成和持续部署时&#xff0c;需要使用Dockerfile生成相关应用程序的镜像。 Dockerfile常用命令 FROM&#xff1a;继承基础镜像MAINTAINER&#xff1a;镜像制作作者的信息&#xff0c;已弃用&a…

文件管理—linux(基础IO)

目录 ​编辑 一、C语言文件接口&#xff08;库函数&#xff09; hello.c写文件 hello.c读文件 输出信息到显示器 stdin & stdout & stderr 二、系统文件I/O&#xff08;系统调用&#xff09; hello.c 写文件&#xff1a; hello.c读文件 接口介绍 open open…

JetBrains PhpStorm 2024 mac/win版:探索PHP之美,智慧编程新境界

JetBrains PhpStorm 2024是一款卓越的PHP集成开发环境(IDE)&#xff0c;专为满足现代PHP开发者的需求而精心打造。它凭借强大的功能和出色的性能&#xff0c;赢得了全球开发者的广泛赞誉。 PhpStorm 2024 mac/win版获取 PhpStorm 2024提供了智能的代码编辑功能&#xff0c;包括…

【TKGQA】关于时间知识图谱问答的一篇综述阅读

前言 时间知识图谱问答&#xff08;TKGQA&#xff09;是KBQA中一个关注时间问题的重要子任务。时间问题包含时间约束、需要时间标记的答案&#xff0c;反映了现实世界事件的动态和演变性质。 一、TKGQA 1.1 概述 时间知识图谱&#xff08;TKG&#xff09;&#xff1a; 通常表…

Android 添加自己的时钟小部件

小部件&#xff0c;也叫微件&#xff0c; 它的介绍参考官网 应用 widget 概览 https://developer.android.google.cn/develop/ui/views/appwidgets/overview?hlzh-cn 直接上图&#xff0c;原生系统上&#xff0c;时钟应用的小部件效果。 我也整一个。 1.创建小部件布局文…

tp5学习基本控制器和视图

1 文件结构 正在上传…重新上传取消 application 主要操作目录 extend 扩展 public 入口文件 runtime 运行时文件 thinkphp 核心代码 vendor 三方扩展 2 public/index.php 解析 正在上传…重新上传取消 .htaccess Apache 可写文件 index.php 主目录 router.php 路由文件 3 inde…

【34W字CISSP备考笔记】域1:安全与风险管理

1.1 理解、坚持和弘扬职业道德 1.1.1.(ISC)职业道德规范 1、行为得体、诚实、公正、负责、守法。 2、为委托人提供尽职、合格的服务。 3、促进和保护职业。 4、保护社会、公益、必需的公信和自信&#xff0c;保护基础设施。 1.1.2.组织道德规范 1、RFC 1087 &#xff0…

乳腺癌患者的生存分析:从传统方法到DeepSurv

一、引言 乳腺癌作为全球女性中最常见的癌症之一&#xff0c;其早期诊断和治疗对于提高患者生存率至关重要。随着医学技术和数据分析方法的不断发展&#xff0c;乳腺癌患者的生存分析逐渐成为研究的热点。通过生存分析&#xff0c;我们可以更好地理解疾病进展、预测患者预后&am…

Python发送HTML邮件有哪些步骤?怎么设置?

Python发送HTML邮件如何实现&#xff1f;Python发送邮件的策略&#xff1f; HTML邮件不仅可以包含丰富的文本格式&#xff0c;还可以插入图片、链接和其他多媒体内容&#xff0c;从而提升邮件的美观性和功能性。AokSend将详细介绍Python发送HTML邮件的主要步骤&#xff0c;帮助…

Redis进阶 - Redis 淘汰策略

我们知道Redis是分布式内存数据库&#xff0c;基于内存运行&#xff0c;可是有没有想过比较好的服务器内存也不过几百G&#xff0c;能存多少数据呢&#xff0c;当内存占用满了之后该怎么办呢&#xff1f;Redis的内存是否可以设置限制&#xff1f; 过期的key是怎么从内存中删除的…

【CSS in Depth2精译】1.4 简写属性

文章目录 1.4 简写属性1.4.1 当心简写属性悄悄覆盖其他样式1.4.2 记住简写值的顺序1 上、右、下、左顺序2 先水平、再垂直的顺序 1.4 简写属性 简写属性&#xff08;Shorthand properties&#xff09; 是可以一次性设置多个属性值的样式属性。例如&#xff0c; font 就是一个简…