数据结构-双向带头循环链表

  • 链表的分类
  • 实现带有哨兵位的双向的循环链表
    • **定义节点的结构**
    • 初始化单个节点
    • 初始化带有哨兵位的双向循环链表
    • 打印链表
    • 销毁链表
    • 尾插
    • 尾删
    • 头插
    • 头删
    • find函数
    • 在任意位置之前插入
    • 任意位置的删除
    • 全部代码
      • list.h
      • list.c
      • test.c
    • 链表和顺序表的区别

链表的分类

如下
在这里插入图片描述
根据上述的三种组合,一共分为8类

实现带有哨兵位的双向的循环链表

定义节点的结构

typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;

初始化单个节点

LTNode* BuyListNode(LTDataType x)
{LTNode* newnode=(LTNode*)malloc(sizeof(LTNode));if (newnode==NULL){perror("malloc fail");}newnode->next = NULL;newnode->prev = NULL;newnode->data = x;return newnode;
}

初始化带有哨兵位的双向循环链表

作用:使链表在无数据的情况下就具有循环的特点

LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}

打印链表

哨兵位phead一定不能为空,否则无法连接下面的节点

void LTPrint(LTNode* phead)
{assert(phead);printf("<=head=>");LTNode* cur = phead->next;while (cur!=phead){printf("%d<=>",cur->data);cur = cur->next;}printf("\n");
}

销毁链表

void LPDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur!=phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);}

尾插

需要三个节点即可布置好顺序
顺序为:tail newnode phead
在这里插入图片描述

void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;}

尾删

增加一个函数用于判断除哨兵位以外是否有其它的节点
bool类型只有两个取值:true和false
需要三个节点,顺序为:tailprev,tail,phead
在这里插入图片描述

bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}void LTPopBack(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->prev;LTNode* tailprev = tail->prev;tailprev->next = phead;phead->prev = tailprev;free(tail);
}

头插

需要三个节点即可布置好顺序
顺序为:phead newnode first

在这里插入图片描述

void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* first = phead->next;newnode->next = first;first->prev = newnode;phead->next = newnode;newnode->prev = phead;
}

头删

增加一个函数用于判断除哨兵位以外是否有其它的节点
bool类型只有两个取值:true和false
需要三个节点,顺序为:phead,tail,tailnex
在这里插入图片描述

void LTPopFront(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->next;LTNode* tailnex = tail->next;phead->next = tailnex;tailnex->prev = phead;free(tail);
}

find函数

从哨兵位的下一个节点开始遍历,直至找到该元素或者遍历到哨兵位结束

LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur!=phead){if (cur->data==x){return cur;}cur = cur->next;}return NULL;
}

在任意位置之前插入

任意位置之前的插入需要搭配find函数来使用,需要三个节点,顺序为:posprev,newnode,pos
可以使用它来进行头插和尾插,分别可以表示为LTInsert(phead->next, x) LTInsert(phead, x)
在这里插入图片描述

void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode= BuyListNode(x);LTNode* posprev = pos->prev;newnode->next = pos;pos->prev = newnode;posprev->next = newnode;newnode->prev = posprev;
}

在这里插入图片描述

任意位置的删除

道理同任意位置的插入
在这里插入图片描述

void LTErase(LTNode* pos)
{assert(pos);LTNode* posprev = pos->prev;LTNode* posnex = pos->next;posprev->next = posnex;posnex->prev = posprev;free(pos);
}

结果如下:
在这里插入图片描述

全部代码

list.h

#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}LTNode;//创建单个的节点
LTNode* BuyListNode(LTDataType x);
//初始化
LTNode* LTInit();
//
void LTPrint(LTNode* phead);
void LPDestroy(LTNode* phead);//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);LTNode* LTFind(LTNode* phead, LTDataType x);//任意位置之前的插入
void LTInsert(LTNode* pos, LTDataType x);
//任意位置的删除
void LTErase(LTNode* pos);

list.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"LTNode* BuyListNode(LTDataType x)
{LTNode* newnode=(LTNode*)malloc(sizeof(LTNode));if (newnode==NULL){perror("malloc fail");}newnode->next = NULL;newnode->prev = NULL;newnode->data = x;return newnode;
}LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}void LTPrint(LTNode* phead)
{assert(phead);printf("<=head=>");LTNode* cur = phead->next;while (cur!=phead){printf("%d<=>",cur->data);cur = cur->next;}printf("\n");
}void LPDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur!=phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);}
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;}bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}void LTPopBack(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->prev;LTNode* tailprev = tail->prev;tailprev->next = phead;phead->prev = tailprev;free(tail);
}void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* first = phead->next;newnode->next = first;first->prev = newnode;phead->next = newnode;newnode->prev = phead;
}void LTPopFront(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->next;LTNode* tailnex = tail->next;phead->next = tailnex;tailnex->prev = phead;free(tail);
}LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);LTNode* cur = phead->next;while (cur!=phead){if (cur->data==x){return cur;}cur = cur->next;}return NULL;
}void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode= BuyListNode(x);LTNode* posprev = pos->prev;newnode->next = pos;pos->prev = newnode;posprev->next = newnode;newnode->prev = posprev;
}void LTErase(LTNode* pos)
{assert(pos);LTNode* posprev = pos->prev;LTNode* posnex = pos->next;posprev->next = posnex;posnex->prev = posprev;free(pos);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "list.h"
void Test1()
{LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPrint(plist);LTPopBack(plist);LTPopBack(plist);LTPrint(plist);
}void Test2()
{LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTPushBack(plist, 4);LTPushFront(plist, 100);LTPushFront(plist, 200);LTPushFront(plist,300);LTPrint(plist);LTPopFront(plist);LTPrint(plist);}
void Test3()
{LTNode* plist = LTInit();LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);LTNode* pos=LTFind(plist, 3);if (pos==NULL){perror("pos NULL");}LTInsert(pos, 100);LTPrint(plist);LTErase(pos);LTPrint(plist);
}
int main()
{//Test1();//Test2();Test3();return 0;
}

链表和顺序表的区别

在这里插入图片描述

局部性原理:加载指定的数据,可能会把与其物理内存之后的数据加载上去。
根据局部性原理,顺序表在载入缓存中时,可能会把与之相邻的数据一同载入,但是,链表的地址并不是相邻的,在载入相应的链表的时候不会把相邻的链表载入缓存。
因此顺序表的缓存利用率比较高。

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

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

相关文章

部署langchain+chatglm

先参考&#xff1a;window零基础部署langchain-ChatGLM_飞奔的屎壳郎的博客-CSDN博客 安装一部分&#xff0c; 1.GCC安装 gcc64位下载 一定要装64位的gcc&#xff0c;因为我的电脑是w10 64位的&#xff0c;装32位运行langchain报错并配置环境变量 可直接用压缩包中的文件&am…

Verilog 学习之路

循环 7-10 代码段 generategenvar i;for (i0; i<8; i i1) begin: my_block_nameassign out[i] in[8-i-1];end endgenerate解释 该代码使用了 S y s t e m V e r i l o g SystemVerilog SystemVerilog 中的 g e n e r a t e generate generate 构造&#xff0c;它允许在…

【软考】系统架构设计风格分类的个人理解

个人适当学习了软考系统架构设计师中关于系统架构设计相关的内容&#xff0c;梳理了一下相关信息。 常见架构类型和常见分类 常见的软考中出现的系统架构列举如下&#xff1a; 分层架构管道-过滤器架构客户端-服务器架构模型-视图-控制器架构&#xff0c;即MVC架构事件驱动架…

行为树(BEHAVIOR TREES)及其工业应用

顾名思义&#xff0c;行为树是描述事物&#xff08;人&#xff0c;动物&#xff0c;机器人&#xff0c;虚拟角色等等&#xff09;行为的树形结构。游戏行业使用行为树为角色行为建模。现在行为树建模技术正在向其它领域渗透&#xff0c;比如工业产线编排&#xff0c;机器人控制…

【从零开始学习C++ | 第二十一篇】C++新增特性 (上)

目录 前言&#xff1a; 委托构造函数&#xff1a; 类内初始化&#xff1a; 空指针&#xff1a; 枚举类&#xff1a; 总结&#xff1a; 前言&#xff1a; C的学习难度大&#xff0c;内容繁多。因此我们要及时掌握C的各种特性&#xff0c;因此我们更新本篇文章&#xff0c;向…

【案例实战】高并发业务的多级缓存架构一致性解决方案

我们在高并发的项目中基本上都离不开缓存&#xff0c;那么既然引入缓存&#xff0c;那就会有一个缓存与数据库数据一致性的问题。 首先&#xff0c;我们先来看看高并发项目里面Redis常见的三种缓存读写模式。 Cache Aside 读写分离模式&#xff0c;是最常见的Redis缓存模式&a…

【状态估计】基于卡尔曼滤波器和扩展卡尔曼滤波器用于 INS/GNSS 导航、目标跟踪和地形参考导航研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【深入探究人工智能】:历史、应用、技术与未来

深入探究人工智能 前言人工智能的历史人工智能的应用人工智能的技术人工智能的未来当代的人工智能产物结语&#x1f340;小结&#x1f340; &#x1f389;博客主页&#xff1a;小智_x0___0x_ &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &am…

LangChain大型语言模型(LLM)应用开发(三):Chains

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

【UE4 塔防游戏系列】10-防御塔升级

目录 效果 步骤 一、根据防御塔等级修改子弹伤害 二、根据防御塔等级修改子弹速度 三、根据防御塔等级修改检测半径 四、根据防御塔等级修改子弹颜色 五、根据防御塔等级修改换弹时间 效果 步骤 一、根据防御塔等级修改子弹伤害 1. 打开“TowerBaseBullet_Child”&…

【ArcGIS Pro二次开发】(48):三调土地利用现状分类面积汇总统计

之前做了一个三调三大类面积统计&#xff0c;有小伙伴反映太粗糙&#xff0c;想要一个完整的地类面积汇总表。 【ArcGIS Pro二次开发】(35)&#xff1a;三调三大类面积统计 本质上并没有多少难度&#xff0c;之前也做过类似的用地用海汇总表&#xff0c;于是拿出来改一改就好了…

window 命令笔记

1.查看端口 输入“netstat -ano”并回车可以获得所有网络连接活动的列表&#xff0c;在表中&#xff0c;本地地址IP地址后方冒号之后的即是端口号&#xff1a; 如果想要查找特定的端口可以输入命令“netstat -aon|findstr “端口号””&#xff0c;例如“netstat -aon|findstr…

My_window类(带有next和quit按钮)

运行代码&#xff1a; //My_window类&#xff08;带有next和quit按钮&#xff09; #include"std_lib_facilities.h" #include"GUI/Simple_window.h" #include"GUI/GUI.h" #include"GUI/Graph.h" #include"GUI/Point.h"//--…

C++基础算法离散化及区间合并篇

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C算法 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 主要讲解了双指针&#xff0c;位运算&#xff0c;离散化以及区间合并。…

有效的括号(C)

bool isValid(char* s) {ST st;StackInit(&st);while (*s) //遍历 -- 与\0终止{//是左括号 压栈if (*s ( || *s [ *s {){StackPush(&st, *s);s;}else{//应对样例&#xff1a; ’]if (StackEmpty(&st)){StackDestroy(&st);return false;}//不是左括号 应该就…

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树、Pipeline、交叉验证

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树案例 除了scikit-learn外&#xff0c;在spark中也提供了机器学习库&#xff0c;即Spark MLlib。 在Spark MLlib机器学习库提供两套算法实现的API&#xff1a;基于RDD API和基于DataFrame API。今天&#xff0c;主要介绍下Data…

docker k8s

Docker docker到底与一般的虚拟机有什么不同呢&#xff1f; 我们知道一般的linux系统即GNU/Linux系统包括两个部分&#xff0c;linux系统内核GNU提供的大量自由软件&#xff0c;而centos就是众多GNU/Linux系统中的一个。 虚拟机会在宿主机上虚拟出一个完整的操作系统与宿主机完…

在 3ds Max 中对链模型进行摆放姿势处理

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 建模和“摆姿势”3D链可能看起来是一项繁琐的工作&#xff0c;但实际上可以通过使用阵列工具并将链中的链接视为骨骼来轻松完成。在本教程中&#xff0c;我将向您展示如何对链条进行建模&#xff0c;并通过…

oled拼接屏在柳州的户外广告中有哪些应用展现?

柳州oled拼接屏是一种高端的显示屏&#xff0c;它采用了OLED技术&#xff0c;具有高亮度、高对比度、高色彩饱和度、高刷新率等优点&#xff0c;能够呈现出更加真实、清晰、细腻的图像效果。 同时&#xff0c;柳州oled拼接屏还具有拼接功能&#xff0c;可以将多个屏幕拼接在一…

vue element select下拉框回显展示数字

vue element select下拉框回显展示数字 问题截图&#xff1a; 下拉框显示数字可以从数据类型来分析错误&#xff0c;接收的数据类型是字符串&#xff0c;但是value是数字类型 <el-form-item prop"classifyLabelId" :label"$t(item.classifyLabelId)"…