当前位置: 首页 > news >正文

数据结构双向链表

在这里插入图片描述

Hello,好久不见,今天我们讲链表的双向链表,这是一个很厉害的链表,带头双向且循环,学了这个链表,你会发现顺序表的头插头删不再是一个麻烦问题,单链表的尾插尾删也变得简单起来了,那废话不多说,让我们开始我们的学习吧!

首先我们要了解它的物理和逻辑结构,那他们的样子是怎样的呢,首先是一个带头的,那这个难道是我们的哨兵位吗,又是双向,且循环,那让我们来画图了解它吧。

在这里插入图片描述

大致就是这样的一个形状,那我们现在需要这样的一个结构体来实现这样的功能,首先应该有一个存储数据的,就是data,然后就是得有两个指针,一个指向前面的节点,一个就是指向后面的节点,那我们就叫它们一个pre指向前面,一个next指向后面,我们来实现一下吧。

typedef int DListType;
typedef struct DList
{struct DList* pre;struct DList* next;DListType data;}DLNode;

为了方便我们写后面的时候结构体方便一点,我们先定义结构体为DLNode,这样更加方便使用。

现在我们要实现下面的各种接口来完成双链表

首先最重要的就是怎么初始化
初始化的话我们先要想想这个接口函数改的参数和返回值
因为是双向链表,所以得有一个head的头节点,这样才能链接后面的内容

初始化双链表

DLNode* DListInit();

接口函数的名字
这里我们分析首先我们得返回值为什么不是void,而是DLNode*
因为我们要在这里面创建一个头节点,这个节点我们后面都得使用,其次还有一个原因就是这样头节点就不会被销毁,当然我们也可以在外面创建一个节点,然后我们在传它的指针进去,对结构体的内容进行修改,都可以达到相同的作用,废话不多说,我们来实现吧!

DLNode* DListInit()
{DLNode* pHead = (DLNode*)malloc(sizeof(DLNode));assert(pHead);pHead->next = pHead;pHead->pre = pHead;
}

其实很简单,这里必须指针指向自己才可以,如果不这样的话,那我们的循环就不能实现了。
接下来就是怎么打印,打印很简单,我们将它这个指针传过去就行了。

打印双链表

void DListPrint(DLNode* pHead)
{assert(pHead);DLNode* cur = pHead->next;while (cur != pHead){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}

打印函数的想法就是我们找head后面的那个节点,然后打印,因为头节点我们不打印,所以取cur开始,因为是循环,所以cur最后会等于pHead,这样的话就是一个循环,所以我们找下一个就行了,然后打印后更新cur。
接下来我们要创建一个节点,这样才能链接起来我们的节点。

DLNode* CreatNewNode(DListType x)
DLNode* CreatNewNode(DListType x)
{DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));assert(newnode);newnode->data = x;newnode->next = NULL;newnode->pre = NULL;return newnode;
}

创造节点好了,接下来就是尾插一个节点进去,我们前面单链表尾插首先要找到尾的位置,然后再去尾插,同时要先找到尾的前一个位置,然后free尾,这样时间复杂度就是O(N),所以效率不是特别高,那我们现在因为head的位置里存放的就是尾的位置,所以不用进行查找了。我们现在来实现一下吧

双链表尾插

void DListPushBACK(DLNode* pHead, DListType x)
{assert(pHead);DLNode* newnode = CreatNewNode(x);DLNode* pre = pHead->pre;pHead->pre = newnode;newnode->next = pHead;pre->next = newnode;newnode->pre = pre;
}

其实尾插也很简单,我们这里先用一个指针保存位置,这样的话下一次插入就可以找到尾的位置,而且还不用注重顺序,这样大大的提升效率

有了尾插那就肯定有头插,一样的办法我们来实现一下

双链表的头插


void DListPushFront(DLNode* pHead, DListType x)
{assert(pHead);DLNode* newnode = CreatNewNode(x);DLNode* next = pHead->next;pHead->next = newnode;newnode->pre = pHead;newnode->next = next;next->pre = newnode;
}

有了头插这些,那肯定还有头删和尾删
那我们也来实现一下吧

尾删

void DListPopBack(DLNode* pHead)
{assert(pHead);if (pHead->next != pHead){DLNode* del = pHead->pre;del->pre->next = pHead;pHead->pre = del->pre;free(del);}
}

前面写的代码都需要测试一下,我们先来测试三个

#include"DList.h"
void test()
{DLNode* head = DListInit();DListPushBack(head, 1);DListPushBack(head, 2);DListPushBack(head, 3);DListPushBack(head, 4);DListPrint(head);DListPushFront(head, 111);DListPushFront(head, 111);DListPushFront(head, 111);DListPrint(head);DListPopBack(head);DListPopBack(head);DListPopBack(head);DListPrint(head);
}
int main()
{test();return 0;
}

发现我们的程序没有问题,我们再来实现一下头删

void DListPopFront(DLNode* pHead)
{assert(pHead);if (pHead->next != pHead){DLNode* del = pHead->next;pHead->next = del->next;del->next->pre = pHead;free(del);}
}

接下来就是双链表的查找,有了查找我们才能和在任意位置的删除和插入连用,那我们现在来实现一下吧


DLNode* DListFind(DLNode* pHead, DListType x)
{assert(pHead);DLNode* cur = pHead->next;while (cur != pHead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

随机插入

void DListInsert(DLNode* pos, DListType x)
{assrt(pos);DLNode* newnode = CreatNewNode(x);DLNode* pospre = pos->pre;pospre->next = newnode;newnode->pre = pospre;newnode->next = pos;pos->pre = newnode;}

也不是随机插入,是在pos位置之前插入,我们直接传pos和x就行,然后在根据之前的想法一步一步的进行插入链接就行

这里可以更新一下头插和尾插,这里就不演示了
那我们在写一个删除pos位置的函数

删除pos位置

void DListPop(DLNode* pos)
{assert(pos);DLNode* pospre = pos->pre;DLNode* posnext = pos->next;pospre->next = posnext;posnext->pre = pospre;free(pos);
}

还有一个destory我们开辟的空间,这个遍历一遍数组, 然后一个一个释放就行,但是会有问题,我们释放的时候必须看要机记住位置,可以从尾巴开始释放,用一个指针记住前面一个的位置,然后释放掉尾巴,然后更新前一个位置,用while控制一下就行了

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int DListType;
typedef struct DList
{struct DList* pre;struct DList* next;DListType data;}DLNode;DLNode* DListInit();void DListPrint(DLNode* pHead);DLNode* CreatNewNode(DListType x);void DListPushBack(DLNode* pHead, DListType x);void DListPushFront(DLNode* pHead, DListType x);void DListPopBack(DLNode* pHead);void DListPopFront(DLNode* pHead);DLNode* DListFind(DLNode* pHead, DListType x);void DListInsert(DLNode* pos, DListType x);void DListPop(DLNode* pos);
#include"DList.h"DLNode* DListInit()
{DLNode* pHead = (DLNode*)malloc(sizeof(DLNode));pHead->next = pHead;pHead->pre = pHead;
}void DListPrint(DLNode* pHead)
{assert(pHead);DLNode* cur = pHead->next;while (cur != pHead){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}DLNode* CreatNewNode(DListType x)
{DLNode* newnode = (DLNode*)malloc(sizeof(DLNode));assert(newnode);newnode->data = x;newnode->next = NULL;newnode->pre = NULL;return newnode;
}void DListPushBack(DLNode* pHead, DListType x)
{DLNode* newnode = CreatNewNode(x);DLNode* pre = pHead->pre;pHead->pre = newnode;newnode->next = pHead;pre->next = newnode;newnode->pre = pre;
}void DListPushFront(DLNode* pHead, DListType x)
{DLNode* newnode = CreatNewNode(x);DLNode* next = pHead->next;pHead->next = newnode;newnode->pre = pHead;newnode->next = next;next->pre = newnode;
}void DListPopBack(DLNode* pHead)
{assert(pHead);if (pHead->next != pHead){DLNode* del = pHead->pre;del->pre->next = pHead;pHead->pre = del->pre;free(del);}
}void DListPopFront(DLNode* pHead)
{assert(pHead);if (pHead->next != pHead){DLNode* del = pHead->next;pHead->next = del->next;del->next->pre = pHead;free(del);}
}DLNode* DListFind(DLNode* pHead, DListType x)
{assert(pHead);DLNode* cur = pHead->next;while (cur != pHead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}void DListInsert(DLNode* pos, DListType x)
{assrt(pos);DLNode* newnode = CreatNewNode(x);DLNode* pospre = pos->pre;pospre->next = newnode;newnode->pre = pospre;newnode->next = pos;pos->pre = newnode;}void DListPop(DLNode* pos)
{assert(pos);DLNode* pospre = pos->pre;DLNode* posnext = pos->next;pospre->next = posnext;posnext->pre = pospre;free(pos);
}

谢谢大家,我们下期再见

相关文章:

数据结构双向链表

Hello&#xff0c;好久不见&#xff0c;今天我们讲链表的双向链表&#xff0c;这是一个很厉害的链表&#xff0c;带头双向且循环&#xff0c;学了这个链表&#xff0c;你会发现顺序表的头插头删不再是一个麻烦问题&#xff0c;单链表的尾插尾删也变得简单起来了&#xff0c;那废…...

解决政务审计大数据传输难题!镭速传输为政务行业提供解决方案

政务行业是国家治理的重要组成部分&#xff0c;涉及到国家安全、社会稳定、民生福祉等方面。随着信息技术的快速发展和革新&#xff0c;政务信息化也迎来了新一轮的升级浪潮。国家相继出台了《国家信息化发展战略纲要》《“十三五”国家信息化规划》《“十四五”推进国家政务信…...

redis 7高级篇1 redis的单线程与多线程

一 redis单线程与多线程 1.1 redis单线程&多线程 1.redis的单线程 redis单线程主要是指Redis的网络IO和键值对读写是由一个线程来完成的&#xff0c;Redis在处理客户端的请求时包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理…...

GO语言:Worker Pools线程池、Select语句、Metex互斥锁详细示例教程

目录标题 一、Buffered Channels and Worker Pools1. Goroutine and Channel Example 线程和通道示例2. Deadlock 死锁3. Closing buffered channels 关闭通道4. Length vs Capacity 长度和容量5. WaitGroup6. Worker Pool Implementation 线程池 二、Select1. Example2. Defau…...

vue ui 创建项目没有反应

问题 cmd中输入 vue ui 没有反应 解决办法 vue ui命令需要vue3.0以上的版本才可以 1、查看当前版本 vue --version vue版本在3.0以下是没有ui命令的 2、查看版本所拥有的命令 vue -h 3、卸载之前版本的vue npm uninstall vue-cli -g 卸载完成&#xff0c;检查是否已经…...

go语言中channel类型

目录 一、什么是channel 二、为什么要有channel 三、channel操作使用 初始化 操作 单向channel 双向channel&#xff0c;可读可写 四、close下什么场景会出现panic 五、总结 一、什么是channel Channels are a typed conduit through which you can send and receive …...

基于STM32F1的电子罗盘HMC5883L角度测量

基于STM32F1的电子罗盘HMC5883L角度测量 参考 1. HMC5883L模块 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Axqqv48y-1692885921487)(…\img\HMC5883L.png)] 型号&#xff1a;GY-271使用芯片&#xff1a;HMCL5883L供电电源&#xff1a;3-5V通…...

Oracle解锁表、包、用户、杀会话、停job

Oracle解锁表、包、用户、杀会话、停job 一、创建包tzq_server_pkg二、授权给需要使用的用户log三、解锁表&#xff1a;执行存过unlock_table(schema_name, table_name)四、解锁包&#xff1a;执行存过unlock_package(schema_name, pkg_name)五、解锁用户&#xff1a;执行存过u…...

软考高级系统架构设计师系列论文九十九:论软件开发平台的选择和应用

软考高级系统架构设计师系列论文九十九:论软件开发平台的选择和应用 一、相关知识点二、摘要三、正文四、总结一、相关知识点 软考高级系统架构设计师系列之:面向构件的软件设计,构件平台与典型架构二、摘要 本文从一个行业MIS系统的开发实践,讨论了软件开发平台的选择和应…...

Redis Pub/Sub 指南

Redis 不仅仅是一个数据库&#xff0c;还可以作为支持发布和订阅&#xff08;Pub/Sub&#xff09;操作的消息代理。本文将使用 Navicat for Redis 简要概述 Redis 的 Pub/Sub 功能。 关于发布或订阅消息范式 Pub/Sub 是一种模式&#xff0c;发送者&#xff08;广播者&#xf…...

Nest(2):Nest 应用目录结构和脚手架命令介绍

Nest 应用目录结构和脚手架命令介绍 在正式使用 NestJS 进行开发之前&#xff0c;先来了解下 Nest 应用的目录结构&#xff0c;和一些常用的脚本命令。 工程目录 下面是使用 nest/cli 创建的 Nest 项目的目录结构。 上篇文章中介绍了 src 目录以及目录下各个文件的作用。下面…...

【嵌入式】MKV31F512VLL12 微控制器 (MCU) 、Cyclone® IV E EP4CE10E22I8LN,FPGA-现场可编程门阵列芯片

1、MKV31F512VLL12 微控制器 (MCU) 是适用于BLDC、PMSM和ACIM电机控制应用的高性能解决方案。这些MCU采用运行频率为100MHz/120MHz、带数字信号处理 (DSP) 和浮点单元 (FPU) 的ARM Cortex-M4内核。KV3x MCU配备两个采样率高达1.2MS/s的16位ADC、多个控制定时器以及512KB闪存。 …...

矢量调制分析基础

前言 本文介绍VSA 的矢量调制分析和数字调制分析测量能力。某些扫频调谐频谱分析仪也能通过使用另外的数字无线专用软件来提供数字调制分析。然而&#xff0c;VSA 通常在调制格式和解调算法配置等方面提供更大的测量灵活性&#xff0c;并提供更多的数据结果和轨迹轨迹显示。本…...

ensp-Ipv6配置配置

ensp-Ipv6配置配置 &#x1f4ce;ipv6.zip&#x1f4ce;Ipv6 网络.docx...

java八股文面试[java基础]—— hashCode 与 equals 区别 == 与 equals的区别

两个对象的hashCode()相同时&#xff0c;equals()相等吗&#xff1f;_两个对象的hashcode一样,equal一样么_不想当个程序员的博客-CSDN博客 equals()&#xff1a;比较的是非基本类型的数据的引用地址&#xff08;即内存地址&#xff09;是否相同&#xff0c;但是对于重写equal…...

Dubbo之PojoUtils源码分析

功能概述 PojoUtils是一个工具类&#xff0c;能够进行深度遍历&#xff0c;将简单类型与复杂类型的对象进行转换&#xff0c;在泛化调用时用到&#xff08;在泛化调用中&#xff0c;主要将Pojo对象与Map对象进行相互转换&#xff09; 功能分析 核心类PojoUtils分析 主要成员…...

【C++】—— C++11新特性之 “右值引用和移动语义”

前言&#xff1a; 本期&#xff0c;我们将要的介绍有关 C右值引用 的相关知识。对于本期知识内容&#xff0c;大家是必须要能够掌握的&#xff0c;在面试中是属于重点考察对象。 目录 &#xff08;一&#xff09;左值引用和右值引用 1、什么是左值&#xff1f;什么是左值引用…...

谈一谈redis脑裂

什么是redis脑裂 &#xff08;1&#xff09;一主多从架构中&#xff0c;主节点与客户端通信正常&#xff0c;主节点与哨兵、从节点连接异常&#xff0c;客户端仍正常写入数据 &#xff08;2&#xff09;哨兵判定主节点下线&#xff0c;重新选主 &#xff08;3&#xff09;原主…...

基于原生Servlet使用模板引擎Thymeleaf访问界面

我们常在Spring Boot项目中使用Thymeleaf模板引擎,今天突发奇想&#xff0c;尝试原生Servlet访问&#xff01; 说做就做 搭建完整的WEB项目 其中的大部分依赖都是后续报错 追加进来的 导入依赖 thymeleaf-3.0.11.RELEASE.jar 第一次访问 访问地址: http://localhost:8080…...

【C语言】15-函数-1

1. 初步认识函数 通过前几章的学习,已经可以编写一些简单的 C 语言程序了,但是如果程序的功能比较多,规模比较大,把所有的程序代码都写在一个主函数(main函数)中,就会使主函数变得庞杂、头绪不清,使阅读和维护程序变得困难。此外,有时程序中要多次实现某一功能就需要…...

08-信息收集-架构、搭建、WAF等

信息收集-架构、搭建、WAF等 信息收集-架构、搭建、WAF等一、前言说明二、CMS识别技术三、源码获取技术四、架构信息获取技术五、站点搭建分析1、搭建习惯-目录型站点2、搭建习惯-端口类站点3、搭建习惯-子域名站点4、搭建习惯-类似域名站点5、搭建习惯-旁注&#xff0c;c段站点…...

Qt --- 显示相关设置 窗口属性等

主界面&#xff0c;窗口 最小化 最大化 关闭按钮、显示状态自定义&#xff1a; setWindowFlags(Qt::CustomizeWindowHint); setWindowFlags(Qt::WindowCloseButtonHint); //只要关闭按钮 setWindowFlags(Qt::WindowFlags type) Qt::FrameWindowHint:没有边框的窗口 Qt::Window…...

使用小程序实现左侧菜单,右侧列表双向联动效果

目录 引言理解双向联动效果的重要性scrollview属性介绍实现左侧菜单数据准备渲染菜单列表监听菜单点击事件实现右侧列表数据结构设计初始数据渲染监听列表滚动事件左侧菜单与右侧列表联动获取当前滚动位置计算对应菜单项联动效果优化用户体验考虑平滑滚动效果菜单高亮状态...

selenium中处理验证码问题

验证码 基本作用&#xff1a;可以实现当前访问页面的数据安全性、还可以减少用户的并发数&#xff1b; 类型&#xff1a;1、纯数字、纯字母&#xff1b;2、汉字组合&#xff1b;3、数学运算题&#xff1b;4、滑动&#xff1b;5、图片&#xff08;选不同的、选相同、成语顺序&…...

EMR电子病历系统 SaaS电子病历编辑器源码 电子病历模板编辑器

EMR&#xff08;Electronic Medical Record&#xff09;指的是电子病历。它是一种基于电子文档的个人医疗记录&#xff0c;可以包括病人的病史、诊断、治疗方案、药物处方、检查报告和护理计划等信息。EMR采用计算机化的方式来存储、管理和共享这些信息&#xff0c;以便医生和医…...

一些自定义hooks

文章目录 1、点击框外隐藏弹窗hook 1、点击框外隐藏弹窗hook **描述&#xff1a;**有一个需要自己封装弹窗的组件&#xff0c;实现点击弹窗框外时隐藏弹窗 代码&#xff1a; import { useEffect } from “react”; // 点击框外hooks import { useEffect } from "react&q…...

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…...

lEC 61068-2-14_2023环境试验.第2-14部分:试验.试验N:温度变化, 最新版发布

https://download.csdn.net/download/m0_67373485/88251313 lEC 61068-2-14_2023环境试验.第2-14部分:试验.试验N:温度变化 A change of temperature test is intended to determine the effect on the specimen of a changeof temperature or a succession of changes of tem…...

CFDEM学习笔记

本文用来记录自己学习CFDEM的笔记。 资料总结 虚拟机&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1MPMTJQfl76mW0H5bbT_rAg 提取码&#xff1a;rqli 开机密码&#xff1a;530944988 知乎博客&#xff1a;作者说明了如何关闭颗粒碰撞计算来达到提升计算速度。 Githu…...

SpringBoot入门篇1 - 简介和工程创建

目录 SpringBoot是由Pivotal团队提供的全新框架&#xff0c; 其设计目的是用来简化Spring应用的初始搭建以及开发过程。 1.创建入门工程案例 ①创建新模块&#xff0c;选择Spring初始化&#xff0c;并配置模块相关基础信息 ②开发控制器类 controller/BookController.jav…...

asp网站后台模板/百度 营销推广怎么做

点击上方“Python大本营”&#xff0c;选择“置顶公众号”Python大本营 IT人的职业提升平台在公众印象中&#xff0c;程序员很忙&#xff0c;没错&#xff01;不过他们忙碌的原因也许并不只是代码&#xff0c;更多因素应归功于这一次又一次的打断&#xff01;以下是网上查到的…...

wordpress如何关闭评论功能/关键词研究工具

目录 软件包分类 软件包分类 源码包 源码包特点 二进制包 二进制包分类 特点 RPM包依赖 软件包分类 软件包分类 源码包二进制包&#xff08;脚本安装包&#xff09; 源码包 源码包什么样 [rootlocalhost ~]# vim hello.c #include <stdio.h> int mai…...

html框架布局实例代码/网站关键词优化排名怎么做

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼上机程序作成概要及要求概要&#xff1a;用C语言编制一个对一系列文件反复读写的命令行程序。命令名称&#xff1a;mkfiles命令形式&#xff1a;mkfiles [filenum生成的文件数] [prefix文件名的前缀][writesz写入数据的size] [writ…...

做动图为所欲为的网站/百度上看了不健康的内容犯法吗

先说下哈&#xff0c;有人说要源代码&#xff0c;源代码在博文《VC开发垃圾文件清理软件之四&#xff1a;程序的界面设计与实现----按钮控件界面》的最后给出下载地址供大家下载。 对应用程序界面的设计包括两部分&#xff0c;一部分是对话框自身的重设计&#xff0c;二是对话框…...

wordpress软件网站模板下载/舆情分析报告范文

访问权限修饰符&#xff1a;private < 默认不写&#xff08;注意不要添加default修饰&#xff09;< protected < public 注意&#xff1a; private > 最小权限&#xff0c;被它修饰的成员只能够在本类中可以访问到 public > 最大权限&#xff0c;任何地方和…...

福田网站制作公司/企业网站seo推广方案

一、信息管理API osal_msg_allocate( )函数原型&#xff1a;任务是分配一个信息缓冲区&#xff0c;当任务调用或函数被调用时&#xff0c;该空间被信息填充或调用信息发送函数osal_msg_send() 发送缓冲空间的信息到其他任务&#xff0c;若该缓冲空间不能被分配&#xff0c;则设…...