C语言简单的数据结构:双向链表的实现

目录:

  • 1.双向链表的结构和初始化
    • 1.1双向链表的结构
    • 1.2双向链表的初始化
  • 2.双向链表的相关操作
    • 2.1双向链表的尾插、打印和头插
      • 2.11双向链表的尾插
      • 2.12双向链表的打印
      • 2.13双向链表的头插
    • 2.2双向链表的尾删和头删
      • 2.21双向链表的尾删
      • 2.22双向链表的头删
    • 2.3双向链表查找和任意位置插入、删除
      • 2.31双向链表查找
      • 2.32双向链表任意位置之后插入
      • 2.33双向链表任意位置删除
    • 2.4双向链表的销毁
  • 本文代码:

1.双向链表的结构和初始化

1.1双向链表的结构

之前我们的单向链表指的是:不带头单向不循环链表
而双向链表指的是:带头双向循环链表
在这里插入图片描述
其中头节点为哨兵位(不存储任何数据),尾部要指向哨兵位
它的节点有:数据,指向下一个节点的指针和指向下一个节点的指针
在这里插入图片描述
这就是双向链表的节点定义,写入VS:
在这里插入图片描述

1.2双向链表的初始化

当双向链表为NULL时,还有一个头节点,说一初始化时就是创建一个哨兵位
在这里插入图片描述

首先是申请链表:
在这里插入图片描述
在这里插入图片描述
接着是哨兵位的创建(放入一个无效数据就行)
在这里插入图片描述
测试:
在这里插入图片描述
在这里插入图片描述

2.双向链表的相关操作

2.1双向链表的尾插、打印和头插

2.11双向链表的尾插

这里的传参是什么呢?
在这里插入图片描述
58c66ffd3020b137a.png)
47be39ed4525a16999a787187d86.png)
对于这个问题其实很简单,对于完成操作来说这两种都可以,但是我们使用第一种是没办法改变哨兵位的,但是我们第二种有机会改变哨兵位的,如果让我们代码更安全一点,就使用第一个

在这里插入图片描述
在这里插入图片描述
这里的d3就是phead指向的prev指针
在这里插入图片描述
我们优先修改newnode指向,然后在修改phead的指向
我们再来判断NULL链表的情况:
当插入NULL指针时,并不会对NULL指针进行解引用,这个代码就没问题
在这里插入图片描述
这两行代码不能直接进行交换,因为会找不到d3这个数据,从而改变不了

2.12双向链表的打印

在这里插入图片描述
在这里插入图片描述
这里要用到哨兵为来确定是否循环一遍
测试:
在这里插入图片描述

2.13双向链表的头插

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
顺序为3 1 4 2
测试:
在这里插入图片描述

2.2双向链表的尾删和头删

在这里插入图片描述

2.21双向链表的尾删

首先要判断链表必须有效并且链表不能为NULL
在这里插入图片描述
在这里插入图片描述
我们只对2 3进行改变就行了
在这里插入图片描述
测试:
在这里插入图片描述

2.22双向链表的头删

在这里插入图片描述
在这里插入图片描述
测试:
在这里插入图片描述

2.3双向链表查找和任意位置插入、删除

2.31双向链表查找

在这里插入图片描述

进行遍历,然后进行判断
测试:
在这里插入图片描述

2.32双向链表任意位置之后插入

在这里插入图片描述
还是对newnode进行改变然后在该pos指针
测试:
在这里插入图片描述

2.33双向链表任意位置删除

删除位置理论上不能为phead,但是没有phead参数,无法增加校验
在这里插入图片描述
也是先将pos后的指针先修改好,然后在修改pos前的指针
测试:
在这里插入图片描述
这里虽然对实参进行改变了,但这里为什么不传二级指针呢
这里是为了保持接口一致性,方便我们的记忆,我们可以通过外部值NULL来解决
在这里插入图片描述
这里我们之前的初始化代码也可以进行优化
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一个以参数的方式初始化,一个以返回值的方法初始化

2.4双向链表的销毁

销毁后要向下走,所以我们要将指针存一下
在这里插入图片描述
这里也是一级指针,所以无法改变头节点
在这里插入图片描述
手动置为NULL即可

本文代码:

List.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;LTNode* LTBuyNode(LTDataType x);//申请空间
//void LTInit(LTNode** pphead);//初始化
LTNode* LTInit();void LTPrint(LTNode* phead);
//插入数据
void LTPushBack(LTNode* phead, LTDataType x);
void LTPushFront(LTNode* phead, LTDataType x);void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);LTNode* LTFind(LTNode* phead, LTDataType x);
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);void LTDestroy(LTNode* phead);

List.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"LTNode* LTBuyNode(LTDataType x)
{//申请节点LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc");exit(1);}node->data = x;node->next = node->prev = node;return node;
}//void LTInit(LTNode** pphead)
//{
//	*pphead = LTBuyNode(-1);
//}LTNode* LTInit()
{LTNode* phead = LTBuyNode(-1);return phead;
}void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead phead->prev newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}void LTPopBack(LTNode* phead)
{//链表必须有效并且链表不能为NULLassert(phead && phead->next != phead);LTNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;free(del);del = NULL;
}LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);newnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}void LTErase(LTNode* pos)
{assert(pos);//pos理论上不能为phead,但是没有phead参数,无法增加校验pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}void LTDestroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}free(phead);phead = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"void ListTest01()
{//LTNode* plist = NULL;//LTInit(&plist);LTNode* plist = LTInit();//LTPushBack(plist, 1);//LTPrint(plist);//LTPushBack(plist, 2);//LTPrint(plist);//LTPushBack(plist, 3);//LTPrint(plist);//LTPushBack(plist, 4);//LTPrint(plist);LTPushFront(plist, 4);LTPrint(plist);LTPushFront(plist, 3);LTPrint(plist);LTPushFront(plist, 2);LTPrint(plist);LTPushFront(plist, 1);LTPrint(plist);LTDestroy(plist);plist = NULL;
}void ListTest02()
{//LTNode* plist = NULL;//LTInit(&plist);LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);//LTPopBack(plist);//LTPrint(plist);//LTPopBack(plist);//LTPrint(plist);//LTPopBack(plist);//LTPrint(plist);//LTPopBack(plist);//LTPrint(plist);LTPopFront(plist);LTPrint(plist);LTPopFront(plist);LTPrint(plist);LTPopFront(plist);LTPrint(plist);LTPopFront(plist);LTPrint(plist);LTDestroy(plist);plist = NULL;
}void ListTest03()
{//LTNode* plist = NULL;//LTInit(&plist);LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);LTNode* find1 = LTFind(plist, 3);if (find1 == NULL){printf("找不到\n");}else{printf("找到了\n");}LTNode* find2 = LTFind(plist, 5);if (find2 == NULL){printf("找不到\n");}else{printf("找到了\n");}LTDestroy(plist);plist = NULL;
}void ListTest04()
{//LTNode* plist = NULL;//LTInit(&plist);LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);LTNode* find1 = LTFind(plist, 2);LTInsert(find1, 66);LTPrint(plist);LTNode* find2 = LTFind(plist, 4);LTInsert(find2, 99);LTPrint(plist);LTNode* find3 = LTFind(plist, 66);LTErase(find3);find3 = NULL;LTPrint(plist);LTNode* find4 = LTFind(plist, 99);LTErase(find4);find4 = NULL;LTPrint(plist);LTDestroy(plist);plist = NULL;
}int main()
{//ListTest01();//ListTest02();//ListTest03();ListTest04();return 0;
}

以上就是本文的全部内容了,希望对大家有所帮助,大家加油!!!

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

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

相关文章

前后端系统开发之——文章管理

原文地址&#xff1a;前后端系统开发之——文章管理 - Pleasure的博客 下面是正文内容&#xff1a; 前言 主要使用的技术&#xff1a;前端使用的是Vue.js&#xff0c;后端使用的是SpringBoot。如不雷同可以直接跳过了。 文章管理是这个系统最主要的一个功能也是最常规的一个功…

如何寻找可靠的第三方软件检测机构

随着科技的飞速发展和数字化进程的加速&#xff0c;软件质量成为了企业竞争的关键。为了确保软件的质量和性能&#xff0c;许多企业选择寻找第三方的软件检测机构来进行软件的质量控制和评估。那么&#xff0c;如何找到一家可靠的第三方软件检测机构呢&#xff1f; 1.明确检测…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

05—js对象

一、初识对象 JavaScript是面向对象编程&#xff08;Object Oriented Programming&#xff0c;OOP&#xff09;语言。 面对象是一种复合值&#xff1a;它将很多值集合在一起&#xff0c;可通过名字访问这些值。对象也可看做一种无序的数据集合&#xff0c;由若干个“键值对”…

数据库--Sqlite3

1、思维导图 2sqlite3在linux中是实现数据的增删&#xff0c;改 #include<myhead.h> int main(int argc, const char *argv[]) { //1、定义一个数据库句柄指针 sqlite3* ppDb NULL; //2、创建或打开数据库 if(sqlite3_open("./mydb…

通过两道题理解哈夫曼树

哈夫曼树定义 哈夫曼树&#xff08;Huffman Tree&#xff09;&#xff0c;又称最优二叉树&#xff0c;是一种带权路径长度最短的二叉树。所谓带权路径长度是指树中所有的叶子结点的权值乘以其到根结点的路径长度&#xff08;边数&#xff09;。哈夫曼树广泛应用于数据压缩等领…

Centroid-Aware Feature Recalibration for Cancer Grading in Pathology Images论文速读

Centroid-Aware Feature Recalibration for Cancer Grading in Pathology Images 摘要 癌症分级是病理学中的一项重要任务。人工神经网络在计算病理学领域的最新发展表明&#xff0c;这些方法在提高癌症诊断的准确性和质量方面具有巨大潜力。然而&#xff0c;这些方法的稳健性…

面试官最怕你懂的Kafka面试题,一招致胜!

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、前言Kafka的优点Kafka的使用场景…

密码学 | 椭圆曲线密码学 ECC 入门(二)

目录 4 椭圆曲线&#xff1a;更好的陷门函数 5 奇异的对称性 6 让我们变得奇特 ⚠️ 原文地址&#xff1a;A (Relatively Easy To Understand) Primer on Elliptic Curve Cryptography ⚠️ 写在前面&#xff1a;本文属搬运博客&#xff0c;自己留着学习。如果你和我一样…

实力认证!亚数产品入选《中国网络安全行业全景图(第十一版)》

2024年4月12日&#xff0c;安全牛第十一版《中国网络安全行业全景图》&#xff08;以下简称“全景图”&#xff09;正式发布。 亚数信息科技&#xff08;上海&#xff09;有限公司&#xff08;以下简称“亚数”&#xff09;成功入选数字证书、加解密、密钥管理三项细分领域。 此…

Linux 2.进程(守护进程)

守护进程 何谓守护进程常见守护进程进程查看命令pskill命令编写简单守护进程守护进程的父进程 何谓守护进程 daemon&#xff0c;表示守护进程&#xff0c;简称为d&#xff08;进程名后面带d的基本就是守护进程&#xff09; 长期运行&#xff08;一般是开机运行直到关机时关闭&…

【Node.js从基础到高级运用】二十五、Node.js中Cluster的作用

引言 Node.js中的cluster模块允许您轻松创建共享服务器端口的子进程。这是一个核心模块&#xff0c;用于在Node.js应用程序中实现多进程架构&#xff0c;以充分利用多核CPU系统的计算能力。 cluster介绍 当您启动一个Node.js应用程序时&#xff0c;默认情况下它运行在单个进程…

【Python】什么是pip,conda,pycharm,jupyter notebook?conda基本教程

pip--conda--pycharm--jupyter notebook &#x1f343;pip&#x1f343;conda&#x1f343;Pycharm&#x1f343;jupyter notebook&#x1f343;Conda基本教程☘️进入base环境☘️创建一个新的环境☘️激活环境☘️退出环境☘️查看电脑上都安装了哪些环境☘️删除已创建的项目…

Mac 部署 GPT-2 预训练模型 gpt2-chinese-cluecorpussmall

文章目录 下载 GPT-2 模型快速开始 GPT-2 下载 GPT-2 模型 https://huggingface.co/uer/gpt2-chinese-cluecorpussmall git clone https://huggingface.co/uer/gpt2-chinese-cluecorpussmall # 或单独下载 LFS GIT_LFS_SKIP_SMUDGE1 git clone https://huggingface.co/uer/gpt…

使用Docker,【快速】搭建个人博客【WordPress】

目录 1.安装Mysql&#xff0c;创建&#xff08;WordPress&#xff09;用的数据库 1.1.安装 1.2.创建数据库 2.安装Docker 3.安装WodPress&#xff08;使用Docker&#xff09; 3.1.创建文件夹 3.2.查看镜像 3.3.获取镜像 3.4.查看我的镜像 3.5.使用下载的镜像&#xf…

Linux的学习之路:11、地址空间

摘要 本章主要是说一下地址空间&#xff0c;我也只是按照我的理解进行解释&#xff0c;可能说不清楚&#xff0c;欢迎指正 目录 摘要 一、空间布局图 二、代码测试一下 三、进程地址空间 四、测试代码 一、空间布局图 如下方图片可以看出地址空间有几种&#xff0c;这里…

Arduino源代码(ino)在Proteus中调试总结

一、前言 基于BluePill Plus开发板&#xff08;该板是毕设网红板&#xff09; BluePill Plus / WeAct Studio 微行工作室 出品 BluePill-Plus/README-zh.md at master WeActStudio/BluePill-Plus GitHub 首页-WeAct Studio-淘宝网 (taobao.com) 在Proteus中对应的例子是&…

每日OJ题_多源BFS①_力扣542. 01 矩阵(多源BFS解决最短路原理)

目录 多源BFS解决最短路算法原理 力扣542. 01 矩阵 解析代码 多源BFS解决最短路算法原理 什么是单源最短路 / 多源最短路&#xff1f; 之前的BFS解决最短路都是解决的单源最短路。 画图来说&#xff0c;单源最短路问题即为&#xff1a; 而对于多源最短路问题: 如何解决此…

Docker容器逃逸-特权模式-危险挂载-Procfs

Docker容器逃逸-特权模式-危险挂载 Docker这个概念&#xff1a; Docker 容器与虚拟机类似&#xff0c;但二者在原理上不同&#xff0c;容器是将操作系统层虚拟化&#xff0c;虚拟机则是虚拟化硬件&#xff0c;因此容器更具有便携性、高效地利用服务器。 ‍ Docker会遇到的安…

京东微服务microApp使用总结

前言 基于现有业务门户进行微服务基础平台搭建 主应用框架&#xff1a;vue3vite 子应用框架&#xff1a;vue2webpack / vue3vite在这里插入代码片 本地调试即可&#xff1a;主应用子应用进行打通&#xff08;注意&#xff1a;两者都是vue3vite&#xff09; 问题总结 1.嵌入…