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的使用场景…

【最新】生成式人工智能(AIGC)与大语言模型(LLM)学习资源汇总

基本概念学习 a) Andrej Karpathy 的 - 大型语言模型简介&#xff1a;https://www.youtube.com/watch?vzjkBMFhNj_g 该视频对 LLMs 进行了一般性和高级的介绍&#xff0c;涵盖推理、缩放、微调、安全问题和提示注入等主题。 b) Nvidia 的生成式 AI 介绍&#xff1a;Course …

密码学 | 椭圆曲线密码学 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;成功入选数字证书、加解密、密钥管理三项细分领域。 此…

python内置库_telnetlib学习笔记

文章目录 介绍实例登录设备执行命令在代码中解决分页问题,并保存日志 常见问题处理分页问题 介绍 官网资料 实例 登录设备执行命令 代码from telnetlib import Telnet######################################## 设置变量 ######################################## hos…

使用 SVG绘制各种图表

1. 折线图 <svg width"400" height"200"><!-- X轴 --><line x1"50" y1"150" x2"350" y2"150" stroke"black" /><!-- Y轴 --><line x1"50" y1"150" x2…

Linux 2.进程(守护进程)

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

【Linux驱动层】iTOP-RK3568学习之路(一):在RK3568上编译内核模块

在RK3568上编译内核模块 helloword.c #include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h>static int helloworld_init(void){printk("helloworld!\n");return 0; }static void helloworld_exit(void){printk("hell…

DeepLab V2: 改进版的DeepLab V1

文章目录 摘要部分概述部分:IntroductionRelated Work详细内容:Methods空洞卷积多尺度问题CRFs,全连接条件随机场实验PASCAL VOC 2012PASCAL-Context数据集PASCAL-Person-Part数据集Cityscapes数据集一些改进空间DeepLab V2版本实际上我理解不算是一个新版本,而是V1版本的作…

【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…

汉译英早操练-(十四)

汉译英早操练-&#xff08;十三&#xff09;-CSDN博客 文接上回。我们上次说了汉译英的时候遇到长难句要先找动词&#xff0c;在找到动词的发出者&#xff0c;重新整理句子&#xff0c;让含义更加明晰&#xff0c;进而用简明英语的原则&#xff0c;表达汉语当中的长难句。 理论…