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

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

双向循环链表

  • 1、带头双向循环链表概念
  • 2、带头双向循环链表的优势
  • 3、带头双向循环链表的实现
    • 3.1、头文件包含和结构定义
    • 3.2、创建新结点
    • 3.3、打印
    • 3.4、初始化
    • 3.5、销毁
    • 3.6、尾插
    • 3.7、头插
    • 3.8、头删
    • 3.9、尾删
    • 3.10、查找
    • 3.11、在pos之前插入
    • 3.12、删除pos位置
    • 3.13、判断是否为空
    • 3.14、计算大小
  • 4、代码汇总
  • 总结

1、带头双向循环链表概念

在这里插入图片描述

概念:带头双向循环链表是一种特殊类型的链表,它由一系列节点组成,每个
节点包含一个数据域和两个指针域,第一个结点不存储有效数据。其中一个指
针指向下一个节点,另一个指针指向前一个节点。在带头双向循环链表中,首
节点的前一个节点是尾节点,尾节点的下一个节点是首节点,形成一个闭环。

2、带头双向循环链表的优势

1.高效遍历:由于带头双向循环链表可以双向遍历,因此可以在O(1)时间内访问任何节点。
2.内存高效:与双向链表相比,带头双向循环链表不需要额外的内存来存储头部节点。
3.插入和删除操作高效:在带头双向循环链表中插入和删除节点时,只需调整指针即可,无需移动大量数据。

3、带头双向循环链表的实现

实现一个带头双向循环链表首先得创建一个工程。(下图为vs 2022)
在这里插入图片描述

List.h(带头双向循环链表的类型定义、接口函数声明、引用的头文件)
List.c(带头双向循环链表接口函数的实现)
test.c (主函数、测试顺序表各个接口功能)
以下是List.h的代码。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}ListNode;//双向链表打印
void ListPrint(ListNode* phead);
//双向链表初始化
ListNode* ListInit();
//双向链表销毁
void ListDestory(ListNode* phead);
//双向链表尾插
void ListPushBack(ListNode* phead, LTDataType x);
//头插
void ListPushFront(ListNode* phead, LTDataType x);
//头删
void ListPopFront(ListNode* phead);
//尾删
void ListPopBack(ListNode* phead);
//查找
ListNode* ListFind(ListNode* phead, LTDataType x);
//在pos之前插入
void ListInsert(ListNode* pos, LTDataType x);
//删除pos位置
void ListErase(ListNode* pos);
//判断是否为空
bool ListEmpty(ListNode* phead);
//计算大小
int ListSize(ListNode* phead);

3.1、头文件包含和结构定义

以下是实现双向循环链表可能用到的头文件。

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

以下是博主创建的双向循环链表的结构,可以根据自己的喜好创建喔。
建议:创建结构时最好能通俗易懂,最好不用拼音创建。

typedef int LTDataType;//定义数据类型,可以根据需要更改
typedef struct ListNode
{LTDataType data;      //数据域 存储数据struct ListNode* next;//指针域 存储指向下一个结点的指针struct ListNode* prev;//指针域 存储指向前一个结点的指针
}ListNode;

3.2、创建新结点

为什么先创建新结点而不是初始化呢?因为当前链表为带头的链表,初始化时需要创建结点,所以就先封装创建结点函数。
在这里插入图片描述

ListNode* BuyList(LTDataType x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}newnode->data = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}

3.3、打印

在这里插入图片描述

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

3.4、初始化

在这里插入图片描述

ListNode* ListInit()
{ListNode* phead = BuyList(0);phead->next = phead;//构成循环phead->prev = phead;//构成循环return phead;
}

3.5、销毁

在这里插入图片描述

void ListDestory(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;while (cur != phead){ListNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;//养成好习惯,释放之后手动置为NULL
}

3.6、尾插

在这里插入图片描述

void ListPushBack(ListNode* phead, LTDataType x)
{assert(phead);//1.创建结点ListNode* newnode = BuyList(x);ListNode* tail = phead->prev;//先找到尾结点//2.链接nexttail->next = newnode;newnode->prev = tail;//3.链接prevnewnode->next = phead;phead->prev = newnode;}

尾插测试
建议养成有初始化函数就有销毁函数的习惯。
在这里插入图片描述

3.7、头插

在这里插入图片描述

void ListPushFront(ListNode* phead, LTDataType x)
{assert(phead);ListNode* newnode = BuyList(x);ListNode* first = phead->next;phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;
}

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

3.8、头删

在这里插入图片描述

void ListPopFront(ListNode* phead)
{assert(phead);assert(phead->next != phead);//没有数据则报错ListNode* first = phead->next;ListNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;
}

测试头删
在这里插入图片描述
在这里插入图片描述

3.9、尾删

在这里插入图片描述

void ListPopBack(ListNode* phead)
{assert(phead);assert(phead->next != phead);ListNode* tail = phead->prev;ListNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}

尾删测试
在这里插入图片描述

3.10、查找

思想:遍历一遍链表,如果该结点的data等于x则返回该结点的地址,遍历一遍没有找到则返回NULL,跟后面在pos位置插入函数结合起来用。

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

3.11、在pos之前插入

跟头插尾插思想差不多,可以自己画图理解理解喔,如果有不理解的可以私信博主喔!这里就没有画图啦!

void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newnode = BuyList(x);ListNode* prev = pos->prev;prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}

测试
在这里插入图片描述

3.12、删除pos位置

void ListErase(ListNode* pos)
{assert(pos);ListNode* prev = pos->prev;ListNode* next = pos->next;prev->next = pos->next;next->prev = prev;
}

在这里插入图片描述

3.13、判断是否为空

bool ListEmpty(ListNode* phead)
{assert(phead);return phead->next == phead;//相等则为真,不相等则为假
}

在这里插入图片描述

3.14、计算大小

思想:创建一个size变量,从头结点的下一个结点遍历链表,不等于头结点则将size++。

int ListSize(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;int size = 0;while (cur != phead){size++;cur = cur->next;}return size;
}

测试
在这里插入图片描述

4、代码汇总

以下是SList.c的代码

//创建结点
ListNode* BuyList(LTDataType x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL){printf("malloc fail\n");exit(-1);}newnode->data = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}
//打印
void ListPrint(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;while (cur != phead){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}
//初始化
ListNode* ListInit()
{ListNode* phead = BuyList(0);phead->next = phead;//构成循环phead->prev = phead;//构成循环return phead;
}
//销毁
void ListDestory(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;while (cur != phead){ListNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;//养成好习惯,释放之后手动置为NULL
}
//尾插
void ListPushBack(ListNode* phead, LTDataType x)
{assert(phead);ListNode* newnode = BuyList(x);ListNode* tail = phead->prev;tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;
}
//头插
void ListPushFront(ListNode* phead, LTDataType x)
{assert(phead);ListNode* newnode = BuyList(x);ListNode* first = phead->next;phead->next = newnode;newnode->prev = phead;newnode->next = first;first->prev = newnode;}
//头删
void ListPopFront(ListNode* phead)
{assert(phead);assert(phead->next != phead);ListNode* first = phead->next;ListNode* second = first->next;phead->next = second;second->prev = phead;free(first);first = NULL;
}
//尾删
void ListPopBack(ListNode* phead)
{assert(phead);assert(phead->next != phead);ListNode* tail = phead->prev;ListNode* prev = tail->prev;prev->next = phead;phead->prev = prev;free(tail);tail = NULL;
}
//查找元素为X的地址
ListNode* ListFind(ListNode* phead, LTDataType x)
{assert(phead);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 = BuyList(x);ListNode* prev = pos->prev;prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}
//删除pos位置
void ListErase(ListNode* pos)
{assert(pos);ListNode* prev = pos->prev;ListNode* next = pos->next;prev->next = pos->next;next->prev = prev;
}
//判断是否为空
bool ListEmpty(ListNode* phead)
{assert(phead);//1.//if (phead->next == phead)//{//	return true;//}//else//{//	return false;//}//2.return phead->next == phead;
}
//获取有效数据个数
int ListSize(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;int size = 0;while (cur != phead){size++;cur = cur->next;}return size;
}

总结

本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

相关文章:

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

双向循环链表 1、带头双向循环链表概念2、带头双向循环链表的优势3、带头双向循环链表的实现3.1、头文件包含和结构定义3.2、创建新结点3.3、打印3.4、初始化3.5、销毁3.6、尾插3.7、头插3.8、头删3.9、尾删3.10、查找3.11、在pos之前插入3.12、删除pos位置3.13、判断是否为空3…...

洛谷——P1347 排序(图论-拓扑排序)

文章目录 一、题目排序题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 提示 二、题解基本思路&#xff1a;代码 一、题目 排序 题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的…...

JVM内存管理

一.java程序运行过程 JDK,JRE,JVM JVM把我们的字节码翻译成机械能执行的机械码。 JRE除了包含JVM之外&#xff0c;还包含很多java的原生依赖库。 JDK除了包含JRE之外&#xff0c;还包含很多工具&#xff0c;比如javac工具。 .java文件是怎么被执行的 我们的.java文件会被…...

将 Python 和 Rust 融合在一起,为 pyQuil® 4.0 带来和谐

文章目录 前言设定方向从 Rust 库构建 Python 软件包改装 pyQuil异步困境回报&#xff1a;功能和性能结论 前言 pyQuil 一直是在 Rigetti 量子处理单元&#xff08;QPUs&#xff09;上构建和运行量子程序的基石&#xff0c;通过我们的 Quantum Cloud Services&#xff08;QCS™…...

Spring Boot应用程序中VO的理解及使用

在Spring Boot应用程序中&#xff0c;VO&#xff08;View Object&#xff09;通常用于表示视图层所需的数据&#xff0c;这些数据来自于业务逻辑层或数据访问层。VO的主要目的是将业务逻辑层的数据结构转换为视图层可以使用的数据结构&#xff0c;使得视图层可以直接使用VO中的…...

华为交换机ETH-TRUNK链路聚合lacp模式与手工模式

SW1配置如下 vlan batch 10interface Eth-Trunk1port link-type trunkport trunk allow-pass vlan 10mode lacp-static #手工模式删除改行max active-linknumber 2 #手工模式删除改行trunkport GigabitEthernet 0/0/1 to 0/0/2#配置为主设备&#xff08;修改优先级&…...

函数图像化

函数图像化 在进行模型提取时&#xff0c;往往会需要选择拟合的函数&#xff0c;因此&#xff0c;了解函数的图像对于模型拟合提取有益&#xff0c;以下是常见的一些函数的曲线 1 二次函数 常见的耳二次函数曲线&#xff0c;转换x与y数量级差异仅一个数量级&#xff0c; 2 三…...

gnu工程的编译 - 以libiconv为例

文章目录 gnu工程的编译 - 以libiconv为例概述gnu官方源码包的发布版从官方的代码库直接迁出的git版源码如果安装了360, 需要添加开发相关的目录到信任区生成 configrue 的方法备注END gnu工程的编译 - 以libiconv为例 概述 gnu工程的下载分2种: gnu官方源码包的发布版 这种…...

在 CentOS 7.8 上安装 Node.js

1.安装 NVM&#xff08;Node Version Manager&#xff09;&#xff1a; curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash这将从 NVM 的 GitHub 仓库下载安装脚本并执行。请注意&#xff0c;您需要重新启动终端或者执行 source ~/.bashrc 以…...

【数据分析实战】冰雪大世界携程景区评价信息情感分析采集词云

文章目录 引言数据采集数据集展示数据预处理 数据分析评价总体情况分析本人浅薄分析 各游客人群占比分析本人浅薄分析 各评分雷达图本人浅薄分析 差评词云-可视化本人浅薄分析 好评词云-可视化本人浅薄分析 综合分析写在最后 今年冬天&#xff0c;哈尔滨冰雪旅游"杀疯了&q…...

BIND-DNS配置介绍

一、主要配置文件 /etc/named.conf options { //Option 段全部配置 listen-on port 53 { 127.0.0.1; };//表示BIND将在53端口监听&#xff0c;若需要对所有IP进行监听&#xff0c;则修改为// listen-on port 53 { any; }; directory "/var/named"…...

Python技巧

Python&#xff0c;现如今非常热门的一种编程语言&#xff0c;在人工智能中大放异彩。做任何事都需要技巧&#xff0c;这可以大大提高效率&#xff0c;学习Python,同样如此&#xff01; 第一个就是assret语句&#xff0c;让我们看下面一个关于折扣的例子&#xff1a; def dic…...

几种常见的CSS三栏布局?介绍下粘性布局(sticky)?自适应布局?左边宽度固定,右边自适应?两种以上方式实现已知或者未知宽度的垂直水平居中?

几种常见的CSS三栏布局 流体布局 效果&#xff1a; 参考代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1…...

箭头函数 - JavaScript的新宠儿

&#x1f4e2; 鸿蒙专栏&#xff1a;想学鸿蒙的&#xff0c;冲 &#x1f4e2; C语言专栏&#xff1a;想学C语言的&#xff0c;冲 &#x1f4e2; VUE专栏&#xff1a;想学VUE的&#xff0c;冲这里 &#x1f4e2; CSS专栏&#xff1a;想学CSS的&#xff0c;冲这里 &#x1f4…...

操作系统期末复习知识点

目录 一.概论 1.操作系统的介绍 2.特性 3.主要功能 4.作用 二.进程的描述与控制 1.进程的定义 2.特性 3.进程的创建步骤 4.基本状态转化 5.PCB的作用 6.进程与线程的比较 三.进程同步 1.同步的概念&#xff08;挺重要的&#xff09; 2.临界区 3.管程和进程的区…...

[英语学习][23][Word Power Made Easy]的精读与翻译优化

[序言] 译者的这次翻译, 完全直译, 生硬无比. [英文学习的目标] 提升自身的英语水平, 对日后编程技能的提升有很大帮助. 希望大家这次能学到东西, 同时加入我的社区讨论与交流英语相关的内容. [原著英文与翻译版对照][第22页] Knowledge is chiefly in the form of words…...

吉林大学19、21级计算机学院《计算机网络》期末真题试题

一、21级&#xff08;考后回忆&#xff09; 一、不定项选择&#xff08;一共10个选择题&#xff0c;一个两分&#xff0c;选全得满分&#xff09; 不定项&#xff1a;可以选择1~4个 考点有&#xff1a; ①协议、服务 ②码分多路复用通过接受码片序列&#xff0c;求哪个站点发送…...

python练习3【题解///考点列出///错题改正】

一、单选题 1.【单选题】 ——可迭代对象 下列哪个选项是可迭代对象&#xff08; D&#xff09;&#xff1f; A.(1,2,3,4,5) B.[2,3,4,5,6] C.{a:3,b:5} D.以上全部 知识点补充——【可迭代对象】 可迭代对象&#xff08;iterable&#xff09;是指可以通过迭代&#xff…...

LINUX服务器防火墙nf_conntrack问题一例

一、故障现象 业务反馈服务异常,无法响应请求&#xff0c;从系统日志 dmesg 或 /var/log/messages 看到大量以下记录&#xff1a;kernel: nf_conntrack: table full, dropping packet. 二、问题分析 业务高峰期服务器访问量大&#xff0c;内核 netfilter 模块 conntrack 相关参…...

经典八股文之RocketMQ

核心概念 NameServer nameserver是整个rocketmq的大脑&#xff0c;是rocketmq的注册中心。broker在启动时向所有nameserver注册。生产者在发送消息之前先从 NameServer 获取 Broker 服务器地址列表(消费者一 样)&#xff0c;然后根据负载均衡算法从列表中选择一台服务器进行消…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

2025年- H71-Lc179--39.组合总和(回溯,组合)--Java版

1.题目描述 2.思路 当前的元素可以重复使用。 &#xff08;1&#xff09;确定回溯算法函数的参数和返回值&#xff08;一般是void类型&#xff09; &#xff08;2&#xff09;因为是用递归实现的&#xff0c;所以我们要确定终止条件 &#xff08;3&#xff09;单层搜索逻辑 二…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录

#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…...