数据结构第六弹---带头双向循环链表
双向循环链表
- 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 提示 二、题解基本思路:代码 一、题目 排序 题目描述 一个不同的值的升序排序数列指的是一个从左到右元素依次增大的…...
JVM内存管理
一.java程序运行过程 JDK,JRE,JVM JVM把我们的字节码翻译成机械能执行的机械码。 JRE除了包含JVM之外,还包含很多java的原生依赖库。 JDK除了包含JRE之外,还包含很多工具,比如javac工具。 .java文件是怎么被执行的 我们的.java文件会被…...
将 Python 和 Rust 融合在一起,为 pyQuil® 4.0 带来和谐
文章目录 前言设定方向从 Rust 库构建 Python 软件包改装 pyQuil异步困境回报:功能和性能结论 前言 pyQuil 一直是在 Rigetti 量子处理单元(QPUs)上构建和运行量子程序的基石,通过我们的 Quantum Cloud Services(QCS™…...
Spring Boot应用程序中VO的理解及使用
在Spring Boot应用程序中,VO(View Object)通常用于表示视图层所需的数据,这些数据来自于业务逻辑层或数据访问层。VO的主要目的是将业务逻辑层的数据结构转换为视图层可以使用的数据结构,使得视图层可以直接使用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#配置为主设备(修改优先级&…...
函数图像化
函数图像化 在进行模型提取时,往往会需要选择拟合的函数,因此,了解函数的图像对于模型拟合提取有益,以下是常见的一些函数的曲线 1 二次函数 常见的耳二次函数曲线,转换x与y数量级差异仅一个数量级, 2 三…...
gnu工程的编译 - 以libiconv为例
文章目录 gnu工程的编译 - 以libiconv为例概述gnu官方源码包的发布版从官方的代码库直接迁出的git版源码如果安装了360, 需要添加开发相关的目录到信任区生成 configrue 的方法备注END gnu工程的编译 - 以libiconv为例 概述 gnu工程的下载分2种: gnu官方源码包的发布版 这种…...
在 CentOS 7.8 上安装 Node.js
1.安装 NVM(Node Version Manager): curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash这将从 NVM 的 GitHub 仓库下载安装脚本并执行。请注意,您需要重新启动终端或者执行 source ~/.bashrc 以…...
【数据分析实战】冰雪大世界携程景区评价信息情感分析采集词云
文章目录 引言数据采集数据集展示数据预处理 数据分析评价总体情况分析本人浅薄分析 各游客人群占比分析本人浅薄分析 各评分雷达图本人浅薄分析 差评词云-可视化本人浅薄分析 好评词云-可视化本人浅薄分析 综合分析写在最后 今年冬天,哈尔滨冰雪旅游"杀疯了&q…...
BIND-DNS配置介绍
一、主要配置文件 /etc/named.conf options { //Option 段全部配置 listen-on port 53 { 127.0.0.1; };//表示BIND将在53端口监听,若需要对所有IP进行监听,则修改为// listen-on port 53 { any; }; directory "/var/named"…...
Python技巧
Python,现如今非常热门的一种编程语言,在人工智能中大放异彩。做任何事都需要技巧,这可以大大提高效率,学习Python,同样如此! 第一个就是assret语句,让我们看下面一个关于折扣的例子: def dic…...
几种常见的CSS三栏布局?介绍下粘性布局(sticky)?自适应布局?左边宽度固定,右边自适应?两种以上方式实现已知或者未知宽度的垂直水平居中?
几种常见的CSS三栏布局 流体布局 效果: 参考代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1…...
箭头函数 - JavaScript的新宠儿
📢 鸿蒙专栏:想学鸿蒙的,冲 📢 C语言专栏:想学C语言的,冲 📢 VUE专栏:想学VUE的,冲这里 📢 CSS专栏:想学CSS的,冲这里 Ǵ…...
操作系统期末复习知识点
目录 一.概论 1.操作系统的介绍 2.特性 3.主要功能 4.作用 二.进程的描述与控制 1.进程的定义 2.特性 3.进程的创建步骤 4.基本状态转化 5.PCB的作用 6.进程与线程的比较 三.进程同步 1.同步的概念(挺重要的) 2.临界区 3.管程和进程的区…...
[英语学习][23][Word Power Made Easy]的精读与翻译优化
[序言] 译者的这次翻译, 完全直译, 生硬无比. [英文学习的目标] 提升自身的英语水平, 对日后编程技能的提升有很大帮助. 希望大家这次能学到东西, 同时加入我的社区讨论与交流英语相关的内容. [原著英文与翻译版对照][第22页] Knowledge is chiefly in the form of words…...
吉林大学19、21级计算机学院《计算机网络》期末真题试题
一、21级(考后回忆) 一、不定项选择(一共10个选择题,一个两分,选全得满分) 不定项:可以选择1~4个 考点有: ①协议、服务 ②码分多路复用通过接受码片序列,求哪个站点发送…...
python练习3【题解///考点列出///错题改正】
一、单选题 1.【单选题】 ——可迭代对象 下列哪个选项是可迭代对象( D)? A.(1,2,3,4,5) B.[2,3,4,5,6] C.{a:3,b:5} D.以上全部 知识点补充——【可迭代对象】 可迭代对象(iterable)是指可以通过迭代ÿ…...
LINUX服务器防火墙nf_conntrack问题一例
一、故障现象 业务反馈服务异常,无法响应请求,从系统日志 dmesg 或 /var/log/messages 看到大量以下记录:kernel: nf_conntrack: table full, dropping packet. 二、问题分析 业务高峰期服务器访问量大,内核 netfilter 模块 conntrack 相关参…...
经典八股文之RocketMQ
核心概念 NameServer nameserver是整个rocketmq的大脑,是rocketmq的注册中心。broker在启动时向所有nameserver注册。生产者在发送消息之前先从 NameServer 获取 Broker 服务器地址列表(消费者一 样),然后根据负载均衡算法从列表中选择一台服务器进行消…...
Pandas之从sql库中导入数据的几种方法分析
1.使用mysql-connector-python库将SQL文件导入到Python中,并查询数据库中的表 确保已经安装mysql-connector-python库 #导入模块 import mysql.connector# 建立与MySQL数据库的连接 conn mysql.connector.connect(host"localhost",user"username&…...
18. Mysql 存储过程,实现动态数据透视
文章目录 概述常见操作创建存储过程存储过程局部变量定义和赋值查看存储过程删除存储过程调用存储过程 示例-动态数据透视详细讲解总结参考资料 概述 Mysql 存储过程是一组预先编译的 sql 语句集合,它们被存储在数据库中,并可以被多次调用执行。存储过程…...
VuePress部署到GitHub Pages
一、git push自动部署 1、创建用于工作流的文件 在项目根目录下创建一个用于 GitHub Actions 的工作流 .yml 文件 name: docson:# 每当 push 到 main 分支时触发部署push:branches: [main]# 手动触发部署workflow_dispatch:jobs:docs:runs-on: ubuntu-lateststeps:- uses: a…...
git 本地仓库
本地仓库 start.bat 启动...
Hive实战:分科汇总求月考平均分
文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、启动Hive Metastore服务2、启动Hive客户端3、创建分区的学生成绩表4、按分区加载数据5、查看分区…...
快速搭建知识付费小程序,3分钟即可开启知识变现之旅
明理信息科技知识付费saas租户平台 在当今数字化时代,知识付费已经成为一种趋势,越来越多的人愿意为有价值的知识付费。然而,公共知识付费平台虽然内容丰富,但难以满足个人或企业个性化的需求和品牌打造。同时,开发和…...
【计算机图形学划重点】第一讲-Pipeline and Introduction
基础知识 Vertex(顶点) define the location of primitives in space, and consists of vertex stream. 顶点用于定义空间中基本图形(primitives)的位置。它包含了一个顶点流(vertex stream),…...
面试题-DAG 有向无环图
有向无环图用于解决前后依赖问题,在Apollo中用于各个组件的依赖管理。 在算法面试中,有很多相关题目 比如排课问题,有先修课比如启动问题,需要先启动1,才能启动2 概念 顶点: 图中的一个点,比…...
vite + vue3引入ant design vue 报错
npm install ant-design-vue --save下载插件并在main.ts 全局引入 报错 解决办法一: main.ts注释掉全局引入 模块按需引入 解决办法二 将package.json中的ant-design-vue的版本^4.0.0-rc.4改为 ^3.2.15版本 同时将将package-lock.json中的ant-design-vue的版本…...
使用EasyPoi导入数据并返回失败xls
添加依赖 <!-- https://mvnrepository.com/artifact/cn.afterturn/easypoi-base --> <dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>4.4.0</version> </dependency> 工…...
网站八个/软文广告是什么
在国家“3060”碳达峰碳中和的政策背景下,如何寻求经济-能源-环境的平衡有效发展是国家、省份、城市及园区等不同级别经济体的重要课题。根据国家政策、当地能源结构、能源技术发展水平以及相关碳排放指标制定合理有效的低碳能源发展规划需要以科学准确的能源环境发…...
给企业做网站赚钱吗/北京seo教师
看懂机器人运动指令1.运动类型J:Joint----关节L: Linear---直线C: Clrcular---圆弧A: Clrcle Arc--- C圆弧2.位置数据P[ ]:一般位置Eg: J P[1] 100% FINEPR[ ]:位置寄存器Eg: J PR[1] 100% FINE3. 速度单位对应不同的动…...
网站后台管理密码忘记/网站关键词优化推广哪家快
编辑 ~/.xine/catalog.cache 文件:sudo gedit ~/.xine/catalog.cache找到[/usr/lib/xine/plugins/1.1.4/xineplug_decode_real_audio.so]把 decoder_priority 后面的数字修改为 10 Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId1776898...
凡科企业邮箱/百度seo引流怎么做
HTTP(十一):数字证书那些事其实这一段时间一直在酝酿这写一些关于数字证书的知识。但是这一块的知识真的是比较杂,因为现在互联网上的证书种类非常的多,压根就没有一个统一的标准。真是公说公有理,婆说婆有…...
查二级建造师个人信息查询/seo是如何优化
SqlHelper详解2008-05-24 10:40SqlHelper 类实现详细信息SqlHelper 类用于通过一组静态方法来封装数据访问功能。该类不能被继承或实例化,因此将其声明为包含专用构造函数的不可继承类。在 SqlHelper 类中实现的每种方法都提供了一组一致的重载。这提供了一种很好的…...
辽宁做网站/windows优化大师使用方法
滚动条的组成: ::-webkit-scrollbar //滚动条整体部分 ::-webkit-scrollbar-thumb // 滚动条里面的小方块,能上下左右移动(取决于是垂直滚动条还是水平滚动条) ::-webkit-scrollbar-track //滚动条的轨道…...