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

带头+双向+循环链表

前言:

前面我们已经学习了单链表的结构及其功能特点,也了解了单链表在实现一些功能时出现的一些缺点,比如在删除某个节点前面一个节点时就需要再开一个变量来存放前面一个节点的信息,这样就显得不灵活,为了使链表实现功能更加灵活,我给来介绍带头双向循环链表,这种链表可以看成是单链表的升级版。

什么是带头双向循环链表?

带头双向循环链表是一种常见的链表数据结构,它是由若干个结点组成的链式数据结构,每个结点包含两个指针,分别指向前一个结点和后一个结点。与普通的单向链表只能单向遍历不同,在双向循环链表中,可以使用前后两个方向进行遍历

带头双向循环链表的优点?

带头链表意味着在链表头部添加一个空的头结点,这个头结点不包含数据,仅包含指向链表首尾结点的指针,它主要作用是简化链表的操作。在插入、删除、查找等操作时,可以直接从头结点开始操作,无需特殊处理首尾结点

双向循环意味着链表的每一个节点都可以随意的找到上一个节点以及下一个节点,并且头节点的前驱指针指向尾节点,尾节点的后驱指针指向头节点,这样整个链表就形成了一个环状结构,可以任意方向遍历整个链表

由于带头双向循环链表具有链表的优点,同时又兼具循环队列的特点,因此在实际应用中被广泛使用。比如在实现 LRU 缓存淘汰算法、模拟双向队列等场景中都有使用。

代码实现

DList.h头文件

各种功能函数的声明以及数据的定义:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType _data;struct ListNode* _next;struct ListNode* _prev;
}ListNode;// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* phead);
// 双向链表打印
void ListPrint(ListNode* phead);
// 双向链表尾插
void ListPushBack(ListNode* phead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* phead);
// 双向链表头插
void ListPushFront(ListNode* phead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* phead);
// 双向链表查找
ListNode* ListFind(ListNode* phead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);

DList.c文件

各种功能函数的具体实现细节:

#include"DList.h"// 创建返回链表的头结点.
ListNode* ListCreate() {ListNode* NewList = (ListNode*) malloc(sizeof(ListNode));if (NewList == NULL) {perror("malloc: fail");}NewList->_data = -1;NewList->_prev = NewList;NewList->_next = NewList;return NewList;
}//创造节点
static ListNode* CreatNode(LTDataType x) {ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL) {perror("malloc:fail");}newnode->_data = x;newnode->_next = newnode;newnode->_prev = newnode;return newnode;
}// 双向链表销毁
void ListDestory(ListNode* phead) {assert(phead);ListNode* cur = phead;cur = cur->_next;while (cur!=phead) {ListNode* temp = cur->_next;cur->_prev->_next = cur->_next;cur->_next->_prev = cur->_prev;free(cur);cur = temp;}free(cur);cur = NULL;
}// 双向链表打印
void ListPrint(ListNode* phead) {assert(phead);ListNode* cur = phead->_next;printf("%d<=>", phead->_data);while (cur!= phead) {printf(" %d <=>", cur->_data);cur = cur->_next;}printf("%d\n", phead->_data);
}// 双向链表尾插
void ListPushBack(ListNode* phead, LTDataType x) {assert(phead);ListNode* newnode = CreatNode(x);ListNode* tail = phead->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = phead;phead->_prev = newnode;
}
// 双向链表尾删
void ListPopBack(ListNode* phead) {assert(phead&&(phead->_next!=phead));ListNode* tail = phead->_prev;phead->_prev = tail->_prev;tail->_prev->_next = phead;free(tail);tail = NULL;
}
// 双向链表头插
void ListPushFront(ListNode* phead, LTDataType x) {assert(phead);ListNode* newnode = CreatNode(x);phead->_next->_prev = newnode;newnode->_next = phead->_next;newnode->_prev = phead;phead->_next = newnode;
}// 双向链表头删
void ListPopFront(ListNode* phead) {assert(phead&&(phead->_next!=phead));ListNode* head = phead->_next;phead->_next->_next->_prev = phead;phead->_next = phead->_next->_next;free(head);head = NULL;
}// 双向链表查找
ListNode* ListFind(ListNode* phead, LTDataType x) {assert(phead && (phead->_next != phead));//ListNode* newnode = CreatNode(x);ListNode* cur = phead->_next;while (cur != phead) {if (cur->_data == x) {return cur;}cur = cur->_next;}return NULL;
}// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x) {assert(pos);ListNode* newnode = CreatNode(x);pos->_prev->_next = newnode;newnode->_prev = pos->_prev;newnode->_next = pos;pos->_prev = newnode;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos) {assert(pos&&(pos->_next!=pos));ListNode* temp = pos;pos->_prev->_next = pos->_next;pos->_next->_prev = pos->_prev;free(temp);temp = NULL;
}

test.c测试文件

分块测试各个部分的功能

#include"DList.h"void test1()//测试尾插、尾删
{// 创建返回链表的头结点.ListNode* phead=NULL;phead= ListCreate();ListPushBack(phead, 1);//尾插ListPushBack(phead, 2);ListPushBack(phead, 3);ListPrint(phead);printf("尾删\n");ListPopBack(phead);//尾删ListPrint(phead);printf("尾删\n");ListPopBack(phead);//尾删ListPrint(phead);//ListPopBack(phead);//ListPrint(phead);ListDestory(phead);//销毁链表
}void test2()//测试头插、头删
{// 创建返回链表的头结点.ListNode* phead = NULL;phead = ListCreate();ListPushFront(phead, 1);//头插,头删ListPushFront(phead, 2);ListPushFront(phead, 3);ListPrint(phead);printf("头删\n");ListPopFront(phead);ListPrint(phead);printf("头删\n");ListPopFront(phead);//ListPopFront(phead);//ListPopFront(phead);//ListPopFront(phead);ListPrint(phead);ListDestory(phead);}
void test3()//测试查找,随机位置插入,随机位置删除
{// 创建返回链表的头结点.ListNode* phead = NULL;phead = ListCreate();//初始化链表数据 1 2 3 4 5ListPushFront(phead, 1);ListPushFront(phead, 2);ListPushFront(phead, 3);ListPushFront(phead, 4);ListPushFront(phead, 5);ListPrint(phead);//ListNode* targetnode = ListFind(phead, 5);ListNode* targetnode = ListFind(phead, 4);if (targetnode == NULL) {//没有找到printf("没有找到\n");}else {printf("找到%d了\n",targetnode->_data);/*ListErase(targetnode);printf("删除这个节点\n");*/ListInsert(targetnode, 10);//在目标节点前面插入printf("在这个节点插入一个数\n");ListPrint(phead);}ListNode* targetnode2 = ListFind(phead, 4);if (targetnode2 == NULL) {//没有找到printf("没有找到\n");}else {printf("找到%d了\n", targetnode2->_data);ListErase(targetnode);printf("删除这个节点\n");ListPrint(phead);}//ListPopFront(phead);//ListPrint(phead);ListDestory(phead);phead = NULL;
}int main() {test1();//test2();//test3();return 0;
}

test1运行结果

在这里插入图片描述

test2运行结果

在这里插入图片描述

test3运行结果

在这里插入图片描述

相关文章:

带头+双向+循环链表

前言&#xff1a; 前面我们已经学习了单链表的结构及其功能特点&#xff0c;也了解了单链表在实现一些功能时出现的一些缺点&#xff0c;比如在删除某个节点前面一个节点时就需要再开一个变量来存放前面一个节点的信息&#xff0c;这样就显得不灵活&#xff0c;为了使链表实现功…...

Leetcode_2:两数相加

题目描述&#xff1a; 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff…...

Pytorch实战教程(一)-神经网络与模型训练

0. 前言 人工神经网络 (Artificial Neural Network, ANN) 是一种监督学习算法,其灵感来自人类大脑的运作方式。类似于人脑中神经元连接和激活的方式,神经网络接受输入,通过某些函数在网络中进行传递,导致某些后续神经元被激活,从而产生输出。函数越复杂,网络对于输入的数…...

【MySQL】手把手教你centos7下载MySQL

centos7下载MySQL 前言正式开始卸载不需要的环境&#xff08;如果你之前没有安装过数据库相关的东西可以跳过&#xff09;下载mysql登录mysql登陆⽅法⼀【不⾏就下⼀个】登陆⽅法⼆【不⾏就下⼀个】登录方式三 前言 安装和卸载MySQL都用系统的root权限&#xff0c;更方便一点&…...

openlayers

OpenLayers使用_openlayers中文官网-CSDN博客...

力扣每日一道系列 --- LeetCode 88. 合并两个有序数组

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅LeetCode每日一道 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 思路1&#xff1a;暴力求解思路2&#xff1a;原地合并 LeetCode 88. 合并两个有序数组…...

Android Studio(项目收获)

取消按钮默认背景色 像按钮默认背景色为深蓝色&#xff0c;即使使用了background属性指定颜色也不能生效。 参考如下的解决方法&#xff1a; 修改/res/values/themes.xml中的指定内容如下&#xff1a; <style name"Theme.TianziBarbecue" parent"Theme.Mater…...

MQ写满的情况如何处理?

**MQ&#xff08;Message Queue&#xff09;**写满的情况通常指消息队列中的存储空间已经被用尽&#xff0c;无法再接收新的消息。处理MQ写满的情况涉及到多个方面&#xff0c;包括监控、调整配置、增加资源、以及处理积压消息等。下面是一些处理MQ写满的 常见方法&#xff1a;…...

点名(缺失的数字),剑指offer,力扣

目录 我们直接看题解吧&#xff1a; 审题目事例提示&#xff1a; 方法&#xff1a; 解题思路&#xff08;二分法&#xff09;&#xff1a; 代码&#xff1a; 方法二&#xff1a;直接遍历 题目地址 LCR 173. 点名 - 力扣&#xff08;LeetCode&#xff09; 今天刷点名&#xff08…...

云安全—Dashboard 攻击面

0x00 前言 众所周知&#xff0c;如果只是一味的REST接口或者命令行话的操作方式&#xff0c;就会变相的提高操作门款&#xff0c;并且不会有很好的呈现方式&#xff0c;所以就有了web ui的方式&#xff0c;也就是Dashboar面板&#xff0c;本篇主要讨论一下关于Dashboar面板的概…...

FCOS难点记录

FCOS 中有计算 特征图&#xff08;Feature map中的每个特征点到gt_box的左、上、右、下的距离&#xff09; 1、特征点到gt_box框的 左、上、右、下距离计算 x coords[:, 0] # h*w&#xff0c;2 即 第一列y coords[:, 1] l_off x[None, :, None] - gt_boxes[..., 0][:, No…...

java通过FTP跨服务器动态监听读取指定目录下文件数据

背景&#xff1a; 1、文件数据在A服务器&#xff08;windows&#xff09;&#xff08;不定期在指定目录下生成&#xff09;&#xff0c;项目应用部署在B服务器&#xff08;Linux&#xff09;&#xff1b; 2、项目应用在B服务器&#xff0c;监听A服务器指定目录&#xff0c;有新…...

5G边缘计算网关的功能及作用

5G边缘计算网关具有多种功能。 首先&#xff0c;它支持智能云端控制&#xff0c;可以通过5G/4G/WIFI等无线网络将采集的数据直接上云&#xff0c;实现异地远程监测控制、预警通知、报告推送和设备连接等工作。 其次&#xff0c;5G边缘计算网关可以采集各种数据&#xff0c;包…...

阿里云AIGC小说生成【必得京东卡】

任务步骤 此文真实可靠不做虚假宣传&#xff0c;绝对真实&#xff0c;可截图为证。 领取任务 链接&#xff08;复制到wx打开&#xff09;&#xff1a;#小程序://ITKOL/1jw4TX4ZEhykWJd 教程实践 打开函数计算控制台 应用->创建应用->人工智能->通义千问 AI 助手-…...

数据结构之AVL树

map/multimap/set/multiset这几个容器有个共同点是: 其底层都是按照二叉搜索树来实现的,但是普通的二叉搜索树有其自身的缺陷, 假如往树中插入的元素有序或者接近有序, 二叉搜索树就会退化成单支树, 时间复杂度会退化成O(N),因此map、set等关联式容器的底层结构是对二叉树进行了…...

如何用Java实现一个基于机器学习的情感分析系统,用于分析文本中的情感倾向

背景&#xff1a;练习两年半&#xff08;其实是两周半&#xff09;&#xff0c;利用工作闲余时间入门一下机器学习&#xff0c;本文没有完整的可实施的案例&#xff0c;由于知识体系不全面&#xff0c;目前代码只能运行&#xff0c;不能准确的预测 卡点&#xff1a; 1 由于过…...

开发聚合支付的的意义

开发聚合支付的意义在于整合各种支付方式&#xff0c;为消费者和商家提供便捷高效的支付体验&#xff0c;同时满足商家的多元化支付需求&#xff0c;提高支付效率和用户体验。 具体来说&#xff0c;聚合支付具有以下意义&#xff1a; 方便快捷&#xff1a;聚合支付整合了多种…...

ChatGPT生产力|中科院学术ChatGPT优化配置

资源链接&#xff1a;GitHub - binary-husky/gpt_academic b站配置讲解链接&#xff1a;chatgpt-academic 新手运行官方精简指南&#xff08;科研chatgpt拓展&#xff09; 某知配置图文讲解&#xff1a;图文详解&#xff1a;在windows中部署ChatGPT学术版 - 知乎 (zhihu.com) 一…...

语音播报speechSynthesis最简单的例子(亲测有用)

最简单的例子&#xff0c;在chrome上亲测有效&#xff1a; const utterThis new SpeechSynthesisUtterance(我来试试呀); const synth window.speechSynthesis; synth.speak(utterThis);加入配置&#xff0c;可以配置语言、音量、语速、音高&#xff0c;继续玩&#xff1a; …...

呆头鹅-全自动视频混剪,批量剪辑批量剪视频,探店带货系统,精细化顺序混剪,故事影视解说,视频处理大全,精细化顺序混剪,多场景裂变,多视频混剪

视频闪闪-全自动视频混剪&#xff0c;探店带货系统&#xff0c;多视频混剪&#xff0c;让你成为视频处理大师&#xff01; 一、全自动视频混剪 www.shipinshanshan.com 你是否曾经厌烦于冗长的视频剪辑过程&#xff1f;是否曾经为了一个短短的混剪视频而熬夜加班&#xff1f;现…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...