数据结构——单链表详解

目录

前言

一.什么是链表

1.概念

​编辑

2.分类

二.单链表的实现(不带头单向不循环链表)

2.1初始化

2.2打印

2.3创建新节点

2.4头插、尾插

2.5头删、尾删

2.6查找

2.7在指定位置之前插入

2.8在指定位置之后插入

2.9删除pos位置

2.10删除pos之后的

2.11销毁链表


前言

通过前面所学的顺序表,我们发现存在着几个问题,顺序表的中间/头部的插入需要挪动数据、扩容存在着性能的消耗、或多或少有空间的浪费,由此我们引入链表这一概念.

一.什么是链表

1.概念

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

2.分类

结构多样,根据是否带头,单向/双向,循环/不循环分为8

其中使用较多的是单链表不带头单向不循环链表)和双向链表(带头双向循环链表),这节讲解单链表的实现

二.单链表的实现(不带头单向不循环链表)

2.1初始化

结构的声明和定义

typedef int SLTDataType;
//该链表由节点组成
typedef struct SListNode
{SLTDataType data;struct SListNode* next;//这里不能写成SLTNode,这时还未重命名
}SLTNode;//typedef struct SListNode SLTNode;

2.2打印

这里有pcur去接收phead,然后依次遍历,当pcur指向NULL时跳出循环,最后再打印NULL

void SLTPrint(SLTNode* phead)
{SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

2.3创建新节点

与顺序表的扩容不同,这里需要新节点即开辟,不会造成浪费

如果开辟失败,则会报错

SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));//新节点if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;return newnode;
}

2.4头插、尾插

头插相较于尾插较容易,这里面传递的是二级指针

//链表的头插、尾插
void SLTPushBack(SLTNode** phead, SLTDataType x);
void SLTPushFront(SLTNode** phead, SLTDataType x);//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//链表为空,新节点为pheadif (*pphead == NULL){*pphead = newnode;return;}//链表不为空,找尾节点SLTNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//为空,跳出循环,此时ptail就是尾节点ptail->next = newnode;
}//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = SLTBuyNode(x);//newnode *ppheadnewnode->next = *pphead;*pphead = newnode;
}

2.5头删、尾删

//链表的头删、尾删
void SLTPopBack(SLTNode** phead);
void SLTPopFront(SLTNode** phead);//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);//链表不为空//链表只有一个节点,有多个节点if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}SLTNode* ptail = *pphead;SLTNode* prev = NULL;while (ptail->next)//prev ptail ptail->next{prev = ptail;ptail = ptail->next;}prev->next = NULL;//销毁尾节点free(ptail);ptail = NULL;
}//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead);//链表不能为空assert(*pphead);//让第二个节点成为新的头//把旧的头节点释放掉SLTNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}

2.6查找

通过遍历链表,查找是否与x相等,若有则返回pcur;若未找到,则返回NULL

//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x)
{assert(pphead);//遍历链表SLTNode* pcur = *pphead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

2.7在指定位置之前插入

与头插类似

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);assert(pos);//要加上链表不为空,若是空链表,那么前面将断言assert(*pphead);SLTNode* newnode = SLTBuyNode(x);//pos刚好是头节点if (pos == *pphead){//头插SLTPushFront(pphead,x);return;}//pos不是头节点的情况SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev->newnode->posprev->next = newnode;newnode->next = pos;
}

2.8在指定位置之后插入

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

2.9删除pos位置

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead);assert(*pphead);assert(pos);//pos刚好是头节点,没有前驱节点,执行头删if (*pphead == pos){//头删SLTPopFront(pphead);return;}SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev pos pos->nextprev->next = pos->next;free(pos);pos = NULL;
}

2.10删除pos之后的

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);//删除链表之后的节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//pos->next不能为空assert(pos->next);//pos pos->next pos->next->nextSLTNode* del = pos->next;free(del);del = NULL;
}

2.11销毁链表

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

如果上述内容对您有帮助,希望给个三连谢谢 

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

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

相关文章

风丘EV能量流测试解决方案 提高电动汽车续航能力

电动汽车(EV)近些年发展迅猛,已被汽车业内普遍认为是未来汽车发展的新方向,但现如今电动汽车仍然存在一些短板,导致其还无法替代传统燃油车。对此,首先想到的肯定就是电动车的续航问题。其实解决电动车续航…

锁(二)队列同步器AQS

一、队列同步器AQS 1、定义 用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。是实现锁的关键。 2、实现 同步器的设计是基于模板方法模式的,也就是说&#…

社交媒体数据治理:Facebook的隐私与透明度

在数字化时代,社交媒体平台扮演着连接人们、传播信息的关键角色。然而,随着社交媒体数据的积累和应用,数据治理的议题逐渐引起了社会的广泛关注。本文将深入探讨Facebook在社交媒体数据治理方面的举措,特别关注其在隐私保护和透明…

Vue代理模式和Nginx反向代理(Vue代理部署不生效)

在使用axios时,经常会遇到跨域问题。为了解决跨域问题,可以在 vue.config.js 文件中配置代理: const { defineConfig } require(vue/cli-service) module.exports defineConfig({transpileDependencies: true,devServer: {port: 7070,prox…

PMP证书含金量如何?到底有啥用处?

接下来就为大家对PMP的一些入门问题做个解答。 01PMP是什么? | PMP是指项目管理专业人士资格认证。 | 美国项目管理协会(PMI)举办的项目管理专业人员(PMP)认证考试。 | 是目前项目管理领域含金量很高的认证。 国内…

实例分割论文阅读之:《Mask Transfiner for High-Quality Instance Segmentation》

1.摘要 两阶段和基于查询的实例分割方法取得了显著的效果。然而,它们的分段掩模仍然非常粗糙。在本文中,我们提出了一种高质量和高效的实例分割Mask Transfiner。我们的Mask Transfiner不是在规则的密集张量上操作,而是将图像区域分解并表示…

cesium系列篇:Entity vs Primitive 源码解析(从Entity到Primitive)02

上篇文章中,我们介绍了使用viewer.entities.add添加entity之后的信号传递以及最后entity对象被传递到GeometryVisualizer; 这篇文章,我们则介绍如何在逐帧渲染的过程中根据GeometryVisualizer中的entity对象创建相应的primitive 这是下文中…

C语言中的内存函数你知道多少呢?

目录 ​编辑 1. memcpy的使用和模拟实现 1.1函数介绍 ​编辑 1.2函数的使用 1.3模拟实现 2. memmove的使用和模拟实现 2.1函数介绍 2.2函数的使用 2.3模拟实现 3. memset函数的使用 3.1函数介绍 3.2函数的使用 ​编辑 4. memcmp函数的使用 4.1函数介绍 4.2函数…

漏电流的检测要求和理解

漏电流的检测要求和理解 简介漏电流的产生和效应标准要求漏电流的试验漏电流与电磁兼容的关系小结 简介 漏电流是指非功能性电流,是非期望的会引起安全方面危险的电流。漏电流表明了设备中电气绝缘起到防电击作用具有的性能,以使穿过电气绝缘的电流控制…

基于spring cloud alibaba的微服务平台架构规划

平台基础能力规划(继续完善更新…) 一、统一网关服务(独立服务) 二、统一登录鉴权系统管理(独立服务) 1.统一登录 2.统一鉴权 3.身份管理 用户管理 角色管理 业务系统和菜单管理 部门管理 岗位管理 字典管…

3D Slicer-最强大的开源医学图像分割工具简要概述

3D Slicer-最强大的开源医学图像分割工具简要概述 本系列涵盖从 3D Slicer 医学图像查看器的基础使用到高级自动分割扩展程序的内容(从入门到高阶!),具体包括软件安装、基础使用教程,自动分割扩展(totalse…

CTFshow web(php命令执行 37-40)

?ceval($_GET[shy]);&shypassthru(cat flag.php); #逃逸过滤 ?cinclude%09$_GET[shy]?>&shyphp://filter/readconvert.base64-encode/resourceflag.php #文件包含 ?cinclude%0a$_GET[cmd]?>&cmdphp://filter/readconvert.base64-encode/…