【数据结构】带头双向链表的实现

 👑个人主页:啊Q闻       

🎇收录专栏:《数据结构》           

 🎉道阻且长,行则将至

前言 

带头双向链表是链表的一种,相较于单链表的实现,其更为简单

一.初识带头双向循环链表

带头双向循环链表结构:

带头双向循环链表的理解:

1.“带头”是指该链表的头节点,这里的头节点,实际上是哨兵位,哨兵位节点不存储任何有效元素。哨兵位存在的意义:遍历循环链表避免死循环。

2.“双向”是指链表中每个节点都有前驱节点和后继节点。

3.“循环”是指链表的首尾是相接的,可以实现一个循环的结构。

二.带头双向循环链表的实现 

节点结构的定义:

带头双向循环链表的实现我们创建三个文件:

一个头文件list.h用于定义链表的结构,链表要实现的接口。

一个源文件list.c用于具体实现链表里定义的接口。

一个源文件test.c用于测试链表。

list.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}LTNode;
void LTInit(LTNode**pphead);//初始化
void LTDestroy(LTNode** pphead);//销毁
void LTPrint(LTNode* phead);//打印
void LTPushBack(LTNode* phead,LTDataType x);//后插
void LTPopBack(LTNode* phead);//后删
void LTPushFront(LTNode* phead,LTDataType x);//前插
void LTPopFront(LTNode* phead);//前删
void LTInsert(LTNode* pos,LTDataType x);//在指定位置插入
void LTErase(LTNode* pos);//在指定位置删除
LTNode* LTFind(LTNode* phead, LTDataType x);//查找


list.c

#include"list.h"
void LTInit(LTNode** pphead)//初始化
{
	*pphead = (LTNode*)malloc(sizeof(LTNode));
	if (*pphead == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	(*pphead)->data = -1;
	(*pphead)->next = (*pphead)->prev = *pphead;
}
LTNode* LTBuyNode(LTDataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode;
}
void LTPrint(LTNode* phead)//打印
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}
void LTPushBack(LTNode* phead, LTDataType x)//后插
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	newnode->next = phead;
	newnode->prev = phead->prev;
	phead->prev->next = newnode;
	phead->prev = newnode;
}
void LTPopBack(LTNode* phead)//后删
{
	assert(phead);
	assert(phead->next!=phead);
	LTNode* del = phead->prev;
	LTNode* prev = del->prev;
	prev->next = phead;
	phead->prev = prev;
	free(del);
	del = NULL;
}
void LTPushFront(LTNode* phead, LTDataType x)//前插
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	newnode->next = phead->next;
	newnode->prev = phead;
	phead->next->prev = newnode;
	phead->next = newnode;

}
void LTPopFront(LTNode* phead)//前删
{
	assert(phead);
	assert(phead->next!=phead);
	LTNode* del = phead->next;
	LTNode* next = del->next;
	next->prev = phead;
	phead->next = next;
	free(del);
	del = NULL;

}
LTNode* LTFind(LTNode* phead, LTDataType x)//查找
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}
void  LTInsert(LTNode* pos, LTDataType x)//在指定位置插入
{
	assert(pos);
	LTNode* newnode = LTBuyNode(x);
	newnode->next = pos->next;
	newnode->prev = pos;
	pos->next->prev = newnode;
	pos->next = newnode;
}
void LTErase(LTNode* pos)//在指定位置删除
{
	assert(pos);
	pos->next->prev = pos->prev;
	pos->prev->next = pos->next;
	free(pos);
	pos = NULL;
}
void LTDestroy(LTNode** pphead)//销毁
{
	assert(pphead);
	assert(*pphead);
	LTNode* pcur = (*pphead)->next;
	while (pcur != *pphead)
	{
		LTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	free(*pphead);
	*pphead = NULL;
}

详解:

初始化:

 创建新节点:

打印:

后插:

后插运行结果:

后删:

后删结果:

前插(所谓前插,是指在哨兵位后边插入):

前插结果:

前删:

前删结果:

查找(查找的函数在后续指定位置删除增加会调用):

在指定位置后插入:

在指定位置后插入结果:

删除指定节点:

删除指定节点运行结果:

销毁链表:

test.c

#include"list.h"
void LTTest01()
{
	LTNode* plist = NULL;
	LTInit(&plist);
	LTPushBack(plist,1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	//LTPopBack(plist);
	/*LTPushFront(plist, 4);
	LTPushFront(plist, 5);
	LTPopFront(plist);*/
	LTNode* pcur = LTFind(plist, 2);
	//LTInsert(pcur,88);
	LTErase(pcur);
	//LTDestroy(&plist);

	LTPrint(plist);
	//LTDestroy(&plist);

}
int main()
{
	LTTest01();
	return 0;
}

谢谢大家阅读,如果有不足之处,欢迎大家在评论区指出。如果对你有帮助的话,希望三连支持一下😁  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【漏洞分析】浅析android手游lua脚本的加密与解密(二)

反编译本人用到的是luajit-decomp,这里需要注意,luajit-decomp默认的lua版本为5.1,luajit版本为2.0.2,我们需要下载对应lua和luajit的版本,编译后替换luajit-decomp下的lua51.dll、luajit.exe、jit文件夹。反编译时需要注意的文件和文件夹: 这里需要下载版本为2.1.0-bet…

用 AI 编程-释放ChatGPT的力量

最近读了本书&#xff0c;是 Sean A Williams 写的&#xff0c;感觉上还是相当不错的。一本薄薄的英文书&#xff0c;还真是写的相当好。如果你想看&#xff0c;还找不到&#xff0c;可以考虑私信我吧。 ChatGPT for Coders Unlock the Power of AI with ChatGPT: A Comprehens…

SAP-CO主数据之统计指标创建-<KK01>

公告&#xff1a;周一至周五每日一更&#xff0c;周六日存稿&#xff0c;请您点“关注”和“在看”&#xff0c;后续推送的时候不至于看不到每日更新内容&#xff0c;感谢。 目录 一、背景&#xff1a; 成本中心主数据创建&#xff1a;传送门 成本要素主数据创建&#xff1…

OpenHarmony实战开发-滑动容器组件Swiper的使用

介绍 本篇Codelab主要介绍了滑动容器组件Swiper的几种常见的应用场景&#xff0c;包括顶部导航、轮播图以及视频滑动播放。 相关概念 Swiper&#xff1a;滑动容器&#xff0c;提供子组件切换滑动的能力。Stack&#xff1a;堆叠容器&#xff0c;子组件按照顺序依次入栈&#x…

康耐视visionpro-CogFindLineTool工具详细说明

CogFindeLineTool功能说明: 检测图像的直线边缘,实现边缘的定位、测量。 CogFindeLineTool操作说明: ①.打开工具栏,双击或点击鼠标拖拽添加CogFindLineTool工具 ②.添加输入图像,点击鼠标右键“链接到”选择输入图像或以连线拖拽的方式选择相应输入图像 ③. 所选空间名…

振弦采集仪在预防地质灾害监测中的作用与应用前景

振弦采集仪在预防地质灾害监测中的作用与应用前景 振弦采集仪&#xff08;String Vibrating Sensor&#xff0c;简称SVM&#xff09;是一种用于地质灾害监测的重要仪器&#xff0c;它通过测量地面振动信号来预测和预警地质灾害的发生。SVM的作用在于提供实时、准确的地质灾害监…

威联通安装Kafka

最近在学习 Kafka 的知识&#xff0c;遇到一些问题网上搜到的信息不全。想要在本地安装一个 Kafka 进行验证&#xff0c;想到了之前买的 Nas 就开始折腾。 用 Docker 的方式安装 Kafka 现在的 Nas 很多都支持 Docker&#xff0c;我买的也支持。威联通的 Docker 叫 Container S…

AugmentedReality之路-通过蓝图启动AR相机(2)

本文实现打开AR相机和关闭AR相机功能&#xff0c;在主界面点击Start AR按钮后打开AR相机&#xff0c;在主界面点击Stop AR按钮后关闭AR相机 1、启动AR相关插件 通过Edit->Plugins启用AugmentedReality下面的所有插件 2、自定义Pawn 在Content->ARBase目录右键&…

如何降低 BlueNRG-LPS 的开机峰值电流

1. 前言 BlueNRG 系列存在开机瞬间会出现很大的峰值电流的现象&#xff0c;预计有 20ma 左右。针对此现象&#xff0c;经常有客户询问该峰值电流会不会导致设备工作异常&#xff1f;会不会导致电池使用寿命缩短&#xff08;考虑到一般纽扣电池能承受的峰值电流大概在 15ma 左右…

B64843-4M 1553B总线 控制时序、寄存器介绍。

B64843-4M系统架构 注: 1 、 CPU ADDRESS LATCH 信号由带地址 / 数据复用总线的处理器提供,对不带地址 / 数据复用总线的处理器,CPU ADDRESS LATCH 信号与 3.3V 信号连接。 2、如果 POLARITY_SEL="1" , RD/信号为高时读使能,为低时写使POLARITY_S…

Codeforces Round 937 (Div. 4)

Codeforces Round 937 (Div. 4) Codeforces Round 937 (Div. 4) A. Stair, Peak, or Neither? 题意&#xff1a;略 思路&#xff1a;照着题模拟&#xff1b; AC code&#xff1a; void solve() {int a, b, c; cin >> a >> b >> c;if (a < b) {if (…

【一种基于改进A*算法和CSA-APF算法的混合路径规划方法】—— 论文阅读

论文题目&#xff1a;A Hybrid Path Planning Method Based on Improved A∗ and CSA-APF Algorithms 1 摘要 大问题&#xff1a;复杂动态环境下全局路径规划难以避开动态障碍物&#xff0c;且局部路径容易陷入局部最优的问题 问题1&#xff1a;针对A*算法产生冗余路径节点和…

基于Python的电商特产数据可视化分析与推荐系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 利用网络爬虫技术从某东采集某城市的特产价格、销量、评论等数据&#xff0c;经过数据清洗后存入数据库&#xff0c;并实现特产销售、市场占有率、价格区间等多维度的可视化统计分析&#xff0c;并…

2024蓝桥杯每日一题(背包2)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;包子凑数 试题二&#xff1a;砝码称重 试题三&#xff1a;倍数问题 试题一&#xff1a;包子称重 【题目描述】 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 N 种蒸笼&#xf…

row_number 函数和关联更新

生成测试数据&#xff0c;房间号数据如下&#xff1a; CREATE TABLE hotel (floor_nbr,room_nbr) ASSELECT 1,100 FROM DUAL UNION ALLSELECT 1,100 FROM DUAL UNION ALLSELECT 2,100 FROM DUAL UNION ALLSELECT 2,100 FROM DUAL UNION ALLSELECT 3,100 FROM DUAL; 里面的房间号…

Ubuntu18.04安装wireshark

安装wireshark 环境Ubuntu18.04 1.使用root用户进行安装 2.将 wireshark-dev/stable PPA 添加到系统的软件源列表中。系统就可以从该PPA获取Wireshark软件包及其更新了。 apt-add-repository ppa:wireshark-dev/stable3.确保你系统上的软件包信息是最新的&#xff0c;这样在…

若依 3.8.7版本springboot前后端分离 整合mabatis plus

1.去掉mybatis 这一步我没有操作&#xff0c;看别人的博客有说不去掉可能冲突&#xff0c;也可能不冲突&#xff0c;我试下来就没去掉如需要去除&#xff0c;到总的pom.xml中properties标签下的<mybatis-spring-boot.version>x.x.x</mybatis-spring-boot.version>…

灰色预测模型以及matlab软件使用

1&#xff0c;灰色系统简介 著名学者邓聚龙教授于20世纪70年代末、80年代初提出&#xff1a; “ The诞生标志:邓教授第一篇灰色系统论文Control Problems of Grey Systems”&#xff0c;发表于北荷兰出版公司期刊 System & Control Letter,1982, No.5. 1.1 灰色系统&…

|行业洞察·香氛|《小红书2023香水香氛营销宝典-71页》

报告内容的详细解读&#xff1a; 行业格局 预计到2025年&#xff0c;香水市场规模将超过300亿&#xff0c;小红书成为香水种草的重要平台。从2018年到2025年&#xff0c;市场规模持续增长&#xff0c;年增速保持在20%左右。香水市场的热度在节日节点尤为明显&#xff0c;如情…

Golang-Gorm-快速上手

Gorm文档 GORM文档地址 安装依赖 go get -u "gorm.io/driver/mysql"go get -u "gorm.io/gorm"连接数据库 默认连接方式 func main() {// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情dsn : "user:passtcp(127.0.0…
最新文章