双链表的实现(数据结构)

链表总体可以分为三大类

一、无头和有头

二、单向和双向

三、循环和不循环

   从上面分类得知可以组合成8种不同类型链表,其中单链表最为简单,双联表最为复杂,两种链表都实现后其余链表都不成问题。

  我们前期博客已将完成了单向无头不循环链表(单链表)的实现,本期博客我们实现双向有头循环链表的实现。

————————————————————————————

说明:

  因为此双链表有头结点,(头结点不存储任何有效数据,双链表中只有头结点时为空链表)

  因此我们无需修改头结点的地址,只需要改变头结点中前驱指针和后面指针的指向即可,所以传参时只需要传头结点的地址即可。

代码实现:

List.h

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

typedef int LTDataType;

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

//void LTInit(LTNode** pphead);
LTNode* LTInit();
void LTDestroy(LTNode* phead);//为了保持接口一致性,需要在外部将phead置空。

//保留头节点其他的删去
void LTClear(LTNode* phead);
LTNode* BuyNode(LTDataType x);

void LTPrint(LTNode* phead);
bool LTEmpty(LTNode* phead);//判断是否为空

void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);

void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);

LTNode* LTFind(LTNode* phead, LTDataType x);

List.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"


LTNode* LTInit()
{
	LTNode* phead = BuyNode(-1);
	return phead;
}

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

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;
}
//清除链表的内容
void LTClear(LTNode* phead)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	phead->next = phead;
	phead->prev = phead;
}
void LTPrint(LTNode* phead)
{
	//链表不能为空
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur!=phead)
	{
		printf("%d->",pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}
bool LTEmpty(LTNode* phead)
{
	if (phead->next = phead)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = BuyNode(x);
	LTNode* ptail = phead->prev;
	ptail->next = newnode;
	newnode->prev = ptail;
	newnode->next = phead;
	phead->prev = newnode;
}
void LTPopBack(LTNode* phead)
{
	assert(phead);
	//链表不能为空
	assert(phead->next!=phead);
	LTNode* ptail = phead->prev;
	LTNode* prev = ptail->prev;
	phead->prev = prev;
	prev->next = phead;
	free(ptail);
	ptail = NULL;
}

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

}
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	LTNode* pos = phead->next;
	LTNode* next = pos->next;
	phead->next = next;
	next->prev = phead;
	free(pos);
	pos = NULL;
}
//在pos位置之后插入数据
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	LTNode* newnode = BuyNode(x);
	LTNode* next = pos->next;
	//pos newnode next
	pos->next = newnode;
	newnode->prev = pos;
	newnode->next = next;
	next->prev = newnode;
}
void LTErase(LTNode* pos)
{
	assert(pos);
	LTNode* prev = pos->prev;
	LTNode* next = pos->next;
	prev->next = next;
	next->prev = prev;
	free(pos);
	pos = NULL;
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur->data!=x && pcur!=phead)
	{
		pcur = pcur->next;
	}
	if (pcur->data == x)
	{
		return pcur;
	}
	else
	{
		return NULL;
	};
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"


int main()
{
	LTNode* phead = LTInit();
	if(LTEmpty(phead))
	{
		printf("链表为空\n");
	}
	LTPushBack(phead,1);
	LTPushBack(phead,2);
	LTPushBack(phead,3);
	LTPushBack(phead,4);
	LTPrint(phead);

	LTPopBack(phead);
	LTPopBack(phead);
	LTPrint(phead);

	LTPopFront(phead);
	LTPrint(phead);

	LTPushFront(phead,100);
	LTPushFront(phead,200);
	LTPushFront(phead,300);
	LTPrint(phead);

	LTNode* ret= LTFind(phead,200);
	if (ret)
	{
		LTErase(ret);
	}
	else
	{
		printf("未找到,无法删除\n");
	}
	LTPrint(phead);

	LTNode* ret2 = LTFind(phead, 2);
	if (ret2)
	{
		LTInsert(ret2, 3);
	}
	else
	{
		printf("未找到,无法插入\n");
	}
	LTPrint(phead);

	LTDestroy(phead);
	phead = NULL;
	return 0;
}

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助

欢迎各位点赞,收藏和关注哦

如果有疑问或有不同见解,欢迎在评论区留言哦

后续我会一直分享双一流211西北大学软件(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享

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

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

相关文章

DNDC土地数据、土壤数据、结果分析、率定验证、土壤碳储量与作物产量、温室气体排放分析、农田减排潜力分析、土地变化下DNDC模拟、气候变化下的DNDC模拟

DNDC模型 DNDC模型是一个用于模拟和追踪农业生态系统中碳氮生物地球化学循环的过程模型&#xff0c;可以用来模拟农业生态系统碳氮排放、农作物产量、土壤固碳作用以及硝酸盐淋失等过程。 模型由两部分组成&#xff1a;第一部分包括土壤气候、植物生长和有机质分解等3个子模型…

二叉搜索树(BST)的创建及增,删,查,改(详解)

目录 初识二叉搜索树&#xff08;BST&#xff09;&#xff1a; 二叉搜索树查找元素&#xff1a; 二叉搜索树修改元素: 二叉搜索树中的增加元素&#xff1a; 二叉搜索树中的删除元素&#xff1a; 初识二叉搜索树&#xff08;BST&#xff09;&#xff1a; 一张图简要概括二…

虚幻4 | 制作游戏——学习记录(一)

1. 启动Epic后下载虚幻4&#xff0c;打开虚幻4后新建一个第三人称游戏项目&#xff0c;效果如下&#xff1a; &#xff08;1&#xff09;内容/ThirdPersonBP/Blueprints中的ThirdPersonCharacter&#xff08;左下角人物&#xff09; 这是模板中使用的主要蓝图类&#xff0c;它…

LED驱动控制芯片SM5166:可消除LED显示模组毛毛虫现象

SM5166是一款LED驱动控制芯片&#xff0c;专为LED显示模组设计&#xff0c;具备多项先进功能。以下是关于SM5166的详细解释&#xff1a; 1. 消除LED显示模组毛毛虫现象&#xff1a;毛毛虫现象是LED显示屏上一种常见的显示问题&#xff0c;表现为在显示动态图像时&#xff0c;L…

LVS (Linux Virtual server)集群介绍

一 集群和分布式 &#xff08;一&#xff09;系统性能扩展方式&#xff1a; Scale UP&#xff1a;垂直扩展&#xff0c;向上扩展,增强&#xff0c;性能更强的计算机运行同样的服务 &#xff08;即升级单机的硬件设备&#xff09; Scale Out&#xff1a;水平扩展&#xff0…

TomCat9的安装与配置

什么是TomCat Tomcat,作为Apache软件基金会下的一个开源项目,是广泛使用的Java Servlet容器和Web服务器。Tomcat提供了运行Java Web应用程序的环境,并且由于其对Servlet和JSP的支持,它成为了许多Java Web应用程序的首选服务器。下面,我们将详细介绍Tomcat的安装与配置过程…

Codeforces Round 932(Div.2) A~E

A.Entertainment in MAC&#xff08;字符串&#xff09; 题意&#xff1a; 恭喜你&#xff0c;你被硕士援助中心录取了&#xff01;但是&#xff0c;你在课堂上感到非常无聊&#xff0c;于是你给自己想了一个游戏。 给你一个字符串 s s s和一个偶数整数 n n n。你可以对它进…

软件测试技术分享 | 测试环境搭建

被测系统的环境搭建&#xff0c;是我们作为软件测试人员需要掌握的技能。 被测系统AUT (Application Under Test) 常见的被测系统即需要被测试的 app&#xff0c;网页和后端服务。大致分为两个方面移动端测试和服务端测试&#xff0c;如下图所示&#xff1a; 常见的被测系统类…

javaSE-----继承和多态

目录 一.初识继承&#xff1a; 1.1什么是继承&#xff0c;为什么需要继承&#xff1a; 1.2继承的概念与语法&#xff1a; 二.成员的访问&#xff1a; 2.1super关键字 2.2this和super的区别&#xff1a; 三.再谈初始化: 小结&#xff1a; 四.初识多态&#xff1a; 4.1多…

RabbitMQ架构详解

文章目录 概述架构详解核心组件虚拟主机&#xff08;Virtual Host&#xff09;RabbitMQ 有几种广播类型 概述 RabbitMQ是⼀个高可用的消息中间件&#xff0c;支持多种协议和集群扩展。并且支持消息持久化和镜像队列&#xff0c;适用于对消息可靠性较高的场合 官网https://www.…

ubuntu22.01安装及配置

前言 本次安装基于VMware Pro 16进行安装。 ubuntu版本&#xff1a;ubuntu-22.04.3-live-server-amd64.iso 1、下载 1.1官网下载 https://ubuntu.com/download 1.2、清华大学镜像网站下载 https://mirrors.tuna.tsinghua.edu.cn/ 进入网站后搜索ubuntu&#xff0c;选择ubu…

谷粒商城【成神路】-【10】——缓存

目录 &#x1f9c2;1.引入缓存的优势 &#x1f953;2.哪些数据适合放入缓存 &#x1f32d;3.使用redis作为缓存组件 &#x1f37f;4.redis存在的问题 &#x1f9c8;5.添加本地锁 &#x1f95e;6.添加分布式锁 &#x1f95a;7.整合redisson作为分布式锁 &#x1f697…

uniapp封装文字提示气泡框toolTip组件

uniapp封装文字提示气泡框toolTip组件 文字提示气泡框&#xff1a;toolTip 因为uniapp 中小程序中没有window对象&#xff0c;需手动调用 关闭 第一种办法关闭&#xff1a;this.$refs.tooltip.close() 第二种办法关闭&#xff1a;visible.sync false 移动端没有现成的toolTip组…

pytorch项目代码记录

目录 1.超过二维的张量写进csv 2.翻转矩阵与绘制热力图 3.切片 4.np按块复制 1.超过二维的张量写进csv #(20,204,273) -> (4080,273) ycsv []for i in range(20):ycsv.append(y[i, 8, :, :].reshape(204,273))with open(y.csv,w,encodingutf-8) as y_obj:writer csv.…

SpringCloud 服务的注册与发现

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第二篇&#xff0c;即使用服务注册和发现的组件&#xff0c;此篇文章会介绍 Eureka、Zookeeper 和 Consu…

C++初阶 类(上)

目录 1. 什么是类 2. 如何定义出一个类 3. 类的访问限定符 4. 类的作用域 5. 类的实例化 6. 类的大小 7. this指针 1.this指针的引出 2. this指针的特性 8. 面试题 1. 什么是类 在C语言中&#xff0c;不同类型的数据集合体是结构体。为了方便管理结构体&#xff0c;我…

CVHub | 万字长文带你全面解读视觉大模型(建议收藏!)

本文来源公众号“CVHub”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;万字长文带你全面解读视觉大模型 0 导读 众所周知&#xff0c;视觉系统对于理解和推理视觉场景的组成特性至关重要。这个领域的挑战在于对象之间的复杂关系…

centos7 python3.12.1 报错 No module named _ssl

https://blog.csdn.net/Amio_/article/details/126716818 安装python cd /usr/local/src wget https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tgz tar -zxvf Python-3.12.1.tgz cd Python-3.12.1/ ./configure -C --enable-shared --with-openssl/usr/local/opens…

Docker镜像及Dockerfile详解

1 Docker镜像用途 统一应用发布的标准格式支撑一个Docker容器的运行 2 Docker镜像的创建方法 基于已有镜像创建基于本地模板创建基于Dockerfile创建 &#xff08;实际环境中用的最多&#xff09; 2.1 基于已有镜像的创建 将容器里面运行的程序及运行环境打包生成新的镜像 …

网络工程师笔记10 ( RIP / OSPF协议 )

RIP 学习路由信息的时候需要配认证 RIP规定超过15跳认定网络不可达 链路状态路由协议-OSPF 1. 产生lsa 2. 生成LSDB数据库 3. 进行spf算法&#xff0c;生成最有最短路径 4. 得出路由表