数据结构->双向链表带你体验开火车(哨兵)与拼接火车(应用)厢的乐趣

✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉

🍎个人主页:橘橙黄又青-CSDN博客

目的:学习双向带头链表的增,删,查,销毁。

1.🍎 双向链表的结构

注意:这⾥的“带头”跟前⾯我们说的“头节点”是两个概念,实际前⾯的在单链表阶段称呼不严 谨,但是为了同学们更好的理解就直接称为单链表的头节点。 带头链表⾥的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这⾥“放哨 的”

 哨兵位”存在的意义: 遍历循环链表避免死循环。

结构图解:

 代码:

2. 🍎双向链表的实现

双向链表的定义结构:

链表空间申请节点,和初始化: 

2.1🍎🍎哨兵位的申请

2.2🍎🍎带头双向链表打印 

我们来分析分析:

 代码:

这里补充一下:为什么是传值?因为临时拷贝一份打印就行,不用打印链表。

 

 2.3🍎🍎双向链表的头插

2.4🍎🍎双向链表的尾插 

尾插一个val尾x的元素

 2.5🍎🍎双向链表的头删

 

 2.6🍎🍎双向链表的尾删

 

2.7🍎🍎双线链表的查找 

2.8🍎🍎双向链表在指定位置插入

 

2.9🍎🍎双向链表删除指定位置节点

2.10🍎🍎 双向链表销毁 

3.🍎项目代码

Test.c

#include"List.h"
void ListTest01() {
	//LTNode* plist = NULL;
	//LTInit(&plist);

	LTNode* plist = LTInit();
	//尾插
	//LTPushBack(plist, 1);
	//LTPushBack(plist, 2);
	//LTPushBack(plist, 3);
	//LTPushBack(plist, 4);
	//LTPrint(plist);
	//头插
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 4);
	LTPrint(plist);       //4->3->2->1->

	//
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//
	//头删
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);

	LTNode* findRet = LTFind(plist, 3);
	/*if (findRet == NULL) {
		printf("未找到!\n");
	}
	else {
		printf("找到了!\n");
	}*/
	在指定位置之后插入数据
	//LTInsert(findRet, 66); //4->3->2->1->66->
	//LTPrint(plist);

	//删除pos位置的节点
	LTErase(findRet);
	LTPrint(plist);
	LTDesTroy(plist);
	plist = NULL;
}

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

List.h代码:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

//定义双向链表中节点的结构
typedef int LTDataType;
typedef struct ListNode {
	LTDataType data;
	struct ListNode* prev;
	struct ListNode* next;
}LTNode;

//注意,双向链表是带有哨兵位的,插入数据之前链表中必须要先初始化一个哨兵位
//void LTInit(LTNode** pphead);
LTNode* LTInit();
//void LTDesTroy(LTNode** pphead);
void LTDesTroy(LTNode* phead);   //推荐一级(保持接口一致性)

void LTPrint(LTNode* phead);

//不需要改变哨兵位,则不需要传二级指针
//如果需要修改哨兵位的话,则传二级指针

//头插,尾插
void LTPushBack(LTNode* phead, LTDataType x);
void LTPushFront(LTNode* phead, LTDataType x);

//头删、尾删
void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);

//查找
LTNode* LTFind(LTNode* phead, LTDataType x);

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
//删除pos位置的数据
void LTErase(LTNode* pos);

List.c代码:

#include"List.h"
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;

	return newnode;
}
//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* LTInit() {
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

//尾插
void LTPushBack(LTNode* phead, LTDataType x) {
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	//phead phead->prev(ptail)  newnode
	newnode->next = phead;
	newnode->prev = phead->prev;

	phead->prev->next = newnode;
	phead->prev = newnode;
}

//头插
void LTPushFront(LTNode* phead, LTDataType x) {
	assert(phead);

	LTNode* newnode = LTBuyNode(x);
	//phead newnode phead->next
	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;
}


//链表打印
void LTPrint(LTNode* phead) {
	//phead不能为空
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}


//尾删
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 LTPopFront(LTNode* phead) {
	assert(phead);
	assert(phead->next != phead);

	LTNode* del = phead->next;
	LTNode* next = del->next;

	//phead 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;
}

//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x) {
	assert(pos);
	LTNode* newnode = LTBuyNode(x);
	//pos newnode pos->next
	newnode->next = pos->next;
	newnode->prev = pos;

	pos->next->prev = newnode;
	pos->next = newnode;
}

//删除pos位置的数据
void LTErase(LTNode* pos) {
	assert(pos);

	//pos->prev pos  pos->next
	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;
//}

//链表销毁
void LTDesTroy(LTNode* phead) {
	//哨兵位不能为空
	assert(phead);

	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	//链表中只有一个哨兵位
	free(phead);
	phead = NULL;
}

感谢观看,都看到这里了,点一个赞,谢谢。

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

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

相关文章

Logseq电脑端+安卓端同步gitee或github

文章目录 0.初衷1.电脑端1.1 新建仓库1.2 克隆项目&#xff0c;生成秘钥1.3 添加图谱&#xff0c;选择文件目录&#xff0c;我是原本就有笔记&#xff0c;所以会如下所示。1.4 下载脚本文件1.5赋权限 &#xff08;windows可跳过&#xff09;1.6 修改脚本命令1.7 logseq设置同步…

从大模型到Agentscope——Multi-Agent框架应用与开发

目录 大模型发展历程 大模型的缺陷 智能体 Agent的构建 模型计划内存工具 Agent到多Agent Multi-Agent 带来性能提升的同时也带来一些新的问题 流程设计鲁棒可靠多模态多系统提升运行效率 Multi-Agent框架 AgentScope Demo 三行代码实现聊天机器人 预告

Python与FPGA——sobel边缘检测

文章目录 前言一、sobel边缘检测二、Python sobel边缘检测三、FPGA sobel边缘检测总结 前言 边缘存在于目标、背景区域之间&#xff0c;它是图像分割所依赖的较重要的依据&#xff0c;也是图像匹配的重要特征。边缘检测在图像处理和计算机视觉中&#xff0c;尤其在图像的特征提…

C++进阶之路---多态(二)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、多态的原理 1.虚函数表 // 这里常考一道笔试题&#xff1a;sizeof(Base)是多少&#xff1f; class Base { public:…

Vue首屏优化方案

在Vue项目中&#xff0c;引入到工程中的所有js、css文件&#xff0c;编译时都会被打包进vendor.js&#xff0c;浏览器在加载该文件之后才能开始显示首屏。若是引入的库众多&#xff0c;那么vendor.js文件体积将会相当的大&#xff0c;影响首屏的体验。可以看个例子&#xff1a;…

后端八股笔记------微服务篇

注册中心的主要作用&#xff1a;根据服务进行负载均衡&#xff0c;服务的健康监控。 服务雪崩&#xff0c;因为一个服务D的宕机&#xff0c;导致很多服务崩掉。 达到失败阈值----Closed_to_Open 服务降级------某一个接口 服务熔断------整个服务 限流常见的算法可以是令牌…

Upload 上传(图片/文件),回显(图片),下载(文件)

1.前端技术&#xff1a;V3 Ant Design Vue 2.后端技术&#xff1a;Java 图片上传/回显&#xff1a; 文件上传回显&#xff1a; 表结构&#xff1a;单文件/图片上传为A表对文件C表 &#xff08;A表field字段 对应 C表id字段&#xff09; 如图&#xff1a;A表中的 vehicle_d…

【测试工具系列】压测用Jmeter还是LoadRunner?还是其他?

说起JMeter&#xff0c;估计很多测试人员都耳熟能详。它小巧、开源&#xff0c;还能支持多种协议的接口和性能测试&#xff0c;所以在测试圈儿里很受欢迎&#xff0c;也是测试人员常用的工具&#xff0c;但是在企业级性能场景下可能会有性能瓶颈&#xff0c;更适合测试自己使用…

基于单片机的视觉导航小车设计

目 录 摘 要 I Abstract II 引 言 1 1 总体方案设计 3 1.1 方案论证 3 1.2 项目总体设计 3 2 项目硬件设计 4 2.1 主控模块设计 4 2.1.1单片机选型 4 2.1.2 STM32F103RCT6芯片 4 2.2单片机最小系统电路 5 2.3电机驱动模块设计 7 2.4红外模块设计 8 2.5红外遥控模块设计 9 2.6超…

一条 SQL 更新语句如何执行的

Server 层 存储引擎层 总流程 查询语句 连接器 查询缓存 分析器 优化器 执行器 更新语句 redo log&#xff08;节省的是随机写磁盘的 IO 消耗&#xff08;转成顺序写&#x…

动态规划刷题总结(入门)

目录 什么是动态规划算法 如何判断题目中将使用动态规划算法&#xff1f; 动态规划题目做题步骤 动态规划题目解析 泰波那契数模型 第 N 个泰波那契数 三步问题 使用最小花费爬楼梯 路径问题 不同路径 不同路径 Ⅱ 珠宝的最高价值 下降最短路径和 地下城游…

【Numpy】练习题100道(1-25题)

#学习笔记# 在学习神经网络的过程中发现对numpy的操作不是非常熟悉&#xff0c;遂找到了Numpy 100题。 Git-hub链接 目录 1 题目列表&#xff1a; 2 题解&#xff1a; 1 题目列表&#xff1a; 导入numpy包&#xff0c;并将其命名为np&#xff08;★☆☆&#xff09; 打印…

设计模式学习笔记 - 规范与重构 - 5.如何通过封装、抽象、模块化、中间层解耦代码?

前言 《规范与重构 - 1.什么情况下要重构&#xff1f;重构什么&#xff1f;又该如何重构&#xff1f;》讲过&#xff0c;重构可以分为大规模高层重构&#xff08;简称 “大型重构”&#xff09;和小规模低层次重构&#xff08;简称 “小型重构”&#xff09;。大型重构是对系统…

3.6研究代码(2)

指的是微电网运行参数。 在MATLAB中&#xff0c;randi([0,1],1,48) 会生成一个包含1*48个0或1的随机整数数组。这意味着数组中的每个元素都将是0或1。 MATLAB帮助中心&#xff1a;均匀分布的伪随机整数 - MATLAB randi - MathWorks 中国https://ww2.mathworks.cn/help/matlab/r…

Java零基础入门到精通_Day 1

01 Java 语言发展史 Java语言是美国Sun公司(StanfordUniversity Network)在1995年推出的 计算机语言Java之父:詹姆斯高斯林(ames Gosling) 重要的版本过度&#xff1a; 2004年 Java 5.0 2014年 Java 8.0 2018年 9月 Java 11.0 &#xff08;目前所使用的&#xff09; 02 J…

llama factory学习笔记

模型 模型名模型大小默认模块TemplateBaichuan27B/13BW_packbaichuan2BLOOM560M/1.1B/1.7B/3B/7.1B/176Bquery_key_value-BLOOMZ560M/1.1B/1.7B/3B/7.1B/176Bquery_key_value-ChatGLM36Bquery_key_valuechatglm3DeepSeek (MoE)7B/16B/67Bq_proj,v_projdeepseekFalcon7B/40B/18…

#LT8711V适用于Type-C/DP1.2/EDP转VGA应用方案,分辨率高达1080P。

1. 概述 LT8711V是一款高性能 Type-C/DP1.2 转 VGA 转换器&#xff0c;设计用于将 USB Type-C 源或 DP1.2 源连接到 VGA 接收器。 该LT8711V集成了一个符合DP1.2标准的接收器和一个高速三通道视频DAC。此外&#xff0c;还包括两个用于 CC 通信的 CC 控制器&#xff0c;以实现 …

文件服务器

文件服务器 # 构建NFS远程共享存储## 一、NFS介绍shell 文件系统级别共享&#xff08;是NAS存储&#xff09; --------- 已经做好了格式化&#xff0c;可以直接用。 速度慢比如&#xff1a;nfs&#xff0c;sambaNFS NFS&#xff1a;Network File System 网络文件系统&#xf…

C++面向对象..

1.面向对象的常见知识点 类、 对象、 成员变量(属性)、成员函数(方法)、 封装、继承、多态 2.类 在C中可以通过struct、class定义一个类 struct和class的区别&#xff1a; struct的默认权限是public(在C语言中struct内部是不可以定义函数的) 而class的默认权限是private(该权…

Windows虚拟机的安装

Windows系统 总结知识点记忆级别&#xff1a; 1级&#xff1a;熟练记忆讲过的所有知识点(按照授课顺序&#xff0c;笔记顺序来提问)2级&#xff1a;灵活应用所学知识点(不按照顺序提问&#xff0c;面临陷阱提问)3级&#xff1a;应用所学知识解决实际问题4级&#xff1a;扩展应…