初阶数据结构之带头+双向+循环链表增删查实现(三)

news2025/1/24 11:04:31

文章目录

    • @[TOC](文章目录)
  • 前言
  • 一、带头双向循环链表的初始化
    • 1.1带头双向循环链表的结构体定义
    • 1.2初始化代码的实现
  • 二、带头+双向+循环链表的增功能实现
    • 2.1头插代码的实现
    • 2.2尾插代码的实现
  • 三、带头+双向+循环链表的打印功能实现
    • 3.1打印代码的实现
  • 四、带头+双向+循环链表删功能实现
    • 4.1头删功能的实现
    • 4.2尾删功能的实现
  • 五、带头+双向+循环链表查功能实现
    • 5.1查功能代码实现
  • 六、最后的代码全过程实现
  • 总结

前言

这篇文章主要讲的就是带头+双向+循环链表增删查改的实现


一、带头双向循环链表的初始化

1.1带头双向循环链表的结构体定义

我们应该知道为什么他叫双向循环链表,因为他有两个指针,一个指向自己的next(也就是下一个),一个是prev(也就是自己的上一个),这样是不是就很方便了呢?对比单链表,单链表的删除就需要定义两个指针来删除,还得从头来删除,而带头双向循环链表就不用那么的麻烦啦。下面是结构体的代码描述

typedef int LTDatatype;
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDatatype data;
}LNode;

1.2初始化代码的实现

首先带头双向循环链表的初始化首先是有一个next,一个prev,这是什么呢?这是一个头指针,一个尾指针,初始化的话可以都先指向自己,如下图所示这就是初始化代码的由来啦。

在这里插入图片描述

LNode* LTInit()
{
	LNode* phead = BuyLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

我们会发现这里有一个BuyLTNode函数,这个函数是用来干什么的呢?这个函数是用来开辟一个新的节点的,那么具体是怎么实现的呢?这里我们用到了malloc函数用来动态开辟一个节点。

LNode* BuyLTNode(LTDatatype x)
{
	LNode* newnode = (LNode*)malloc(sizeof(LNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

二、带头+双向+循环链表的增功能实现

2.1头插代码的实现

void LTPustFront(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* newnode = BuyLTNode(x);
	LNode* first = phead->next;
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

我们要进行带头双向循环链表的头插,那么我们应该怎么样头插呢?很多人会认为是在phead那一个指针进行头插,实则并不然,应该是在phead与p之间才是对的,那么我们应该怎么操作才能把我们newnode的节点头插进去呢?首先我们应该找到first,也就是phead->next,我们为什么要找到这一个节点呢?因为我们要在phead和p之间头插所以first这个节点我们必须得是知道的,而且找到这个节点也是有好处的,有什么好处呢?找到这个节点我们就能知道这个节点的位置,之后的操作也会方便很多。

在这里插入图片描述在这里插入图片描述

先将cur定义出来,也就是LNode* cur = phead->next;,其次在链接就行啦,phead->next = newnode,newnode->prev = phead,newnode->next = cur,cur->next = newnode;这里的p指针要根据图来链接哦!

2.2尾插代码的实现

void LTPustBack(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* tail = phead->prev;
	LNode* newnode = BuyLTNode(x);

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

尾插:顾名思义就是在尾部插入,那么双向带头循环链表有啥优势呢?我们可以直接从头就可以找到尾,就不像单链表需要从头开始找了。如下图所示

这是未插入之前:
在这里插入图片描述
这是插入之后:
在这里插入图片描述

该图把尾指针的next链接到newnode上,再把头指针的链接链到新开的newnode的节点上。这里我们还需要找到未插入之前的尾节点,那么我们应该怎么找到尾节点呢?LNode* tail = phead->prev;这样我们是不是就能找到尾节点了呢?

三、带头+双向+循环链表的打印功能实现

3.1打印代码的实现

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

因为我们是带有双向循环链表,我们的最后一个节点,会重新指向头结点,我们只需要把遍历的继续条件设为cur!=phead时就行啦。

四、带头+双向+循环链表删功能实现

4.1头删功能的实现

首先,我们应该怎么样进行头删呢?既然遇到解决不了的事情,我们选择画图来进行理解吧

在这里插入图片描述

void LTPopFront(LNode* phead)
{
	assert(phead);
	LNode* first = phead->next;
	LNode* second = first->next;
	phead->next = second;
	second->prev = phead;
	free(first);
}

4.2尾删功能的实现

在这里插入图片描述

void LTPopBack(LNode* phead)
{
	assert(phead);
	LNode* tail = phead->prev;
	LNode* tailprev = tail->prev;
	free(tail);
	phead->prev = tailprev;
	tailprev->next = phead;
}

五、带头+双向+循环链表查功能实现

5.1查功能代码实现

其实查找功能也就是遍历一遍所有的节点,找到我们想要的值,然后返回就行啦。

LNode* LTFind(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

六、最后的代码全过程实现

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"

void TestList1()
{
	LNode* plist = LTInit();
	LTPustBack(plist, 1);
	LTPustBack(plist, 2);
	LTPustBack(plist, 3);
	LTPustBack(plist, 4);
	LTPrint(plist);
	
	LTPopBack(plist);
	LTPrint(plist);
}

void TestList2()
{
	LNode* plist = LTInit();
	LTPustFront(plist, 1);
	LTPustFront(plist, 2);
	LTPustFront(plist, 3);
	LTPustFront(plist, 4);
	LTPrint(plist);

	LTPopFront(plist);
	LTPrint(plist);
	LNode* pos = LTFind(plist, 3);
	//LTInsert(pos, 4);
	LTErase(pos);
	LTPrint(plist);
}

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

list.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int LTDatatype;
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDatatype data;
}LNode;


LNode* LTInit();
void LTPustBack(LNode* phead, LTDatatype x);
void LTPustFront(LNode* phead, LTDatatype x);
void LTPopBack(LNode* phead);
void LTPopFront(LNode* phead);
void LTPrint(LNode* phead);

void LTInsert(LNode* pos, LTDatatype x);
LNode* LTFind(LNode* phead, LTDatatype x);
void LTErase(LNode* pos);

list.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"

LNode* BuyLTNode(LTDatatype x)
{
	LNode* newnode = (LNode*)malloc(sizeof(LNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

LNode* LTInit()
{
	LNode* phead = BuyLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

void LTPustBack(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* tail = phead->prev;
	LNode* newnode = BuyLTNode(x);

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}
void LTPrint(LNode* phead)
{
	assert(phead);
	LNode* cur = phead->next;
	printf("phead<==>");
	while (cur != phead)
	{
		printf("%d<==>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

//void LTPustFront(LNode* phead, LTDatatype x)
//{
//	assert(phead);
//	LNode* newnode = BuyLTNode(x);
//	newnode->next = phead->next;
//	phead->next->prev = newnode;
//	phead->next = newnode;
//	newnode->prev = phead;
//
//}
void LTPustFront(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* newnode = BuyLTNode(x);
	LNode* first = phead->next;
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}
void LTPopBack(LNode* phead)
{
	assert(phead);
	LNode* tail = phead->prev;
	LNode* tailprev = tail->prev;
	free(tail);
	phead->prev = tailprev;
	tailprev->next = phead;
}

void LTPopFront(LNode* phead)
{
	assert(phead);
	LNode* first = phead->next;
	LNode* second = first->next;
	phead->next = second;
	second->prev = phead;
	free(first);
}

LNode* LTFind(LNode* phead, LTDatatype x)
{
	assert(phead);
	LNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void LTInsert(LNode* pos, LTDatatype x)
{
	assert(pos);
	LNode* prev = pos->prev;
	LNode* newnode = BuyLTNode(x);

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

void LTErase(LNode* pos)
{
	assert(pos);
	LNode* tail = pos->next;
	LNode* prev = pos->prev;
	prev->next = tail;
	tail->prev = prev;
}




总结

今天带大家了解了数据结构的带头双向循环链表的增删查,其中该数据结构还有随机插入和随机删除我没讲解,大家有不懂的可以评论区留言啦!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国开电大《WEB开发基础》形考任务【答案】实验1-5:电商网站前端页面内容编写

国开电大《WEB开发基础》形考任务1 国开电大《WEB开发基础》形考任务1 国开电大《WEB开发基础》形考任务3 国开电大《WEB开发基础》形考任务4 国开电大《WEB开发基础》形考任务5 作业答案 联系QQ:1603277115 【目标】根据素材中的设计图&#xff0c;编写网站首页&#xff0c;查…

AcWing算法提高课-1.3.6货币系统

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 给你一个n种面值的货币系统&#xff0c;求组成面值为m的货币有多少种方案。 输入格式 第一行&#xff0c;包含两个整数n和m。 接…

Vue3-黑马(七)

目录&#xff1a; &#xff08;1&#xff09;vue3-基础-子组件1 &#xff08;2&#xff09;vue3-基础-子组件2 &#xff08;3&#xff09;vue3-进阶-antdv-入门 &#xff08;1&#xff09;vue3-基础-子组件1 之前我们的例子里只使用了一个vue的组件&#xff0c;那么在这个…

近40个开源的工业软件-工业4.0

不同的工业流程&#xff0c;需要不同的工业软件。面向研发设计环节的开源软件&#xff0c;今天就来介绍一下面向生产控制环节的开源软件&#xff0c;主要为可编程逻辑控制器&#xff08;PLC)、分布式控制系统&#xff08;DCS&#xff09;、生产执行系统&#xff08;MES&#xf…

人工智能(AI)的应用以及前景

当今世界正迎来人工智能技术的全面爆发&#xff0c;它在各个领域的应用已经展现出了巨大的潜力和优势。下面&#xff0c;我们来探讨一下人工智能在不同领域中的应用。 首先&#xff0c;人工智能在医疗领域中的应用已经逐渐成为了现实。医疗机构可以利用人工智能技术&#xff0…

Java学习(13)(异常的概念、异常的体系结构、异常的分类、异常的处理【防御式编程、异常的抛出、异常的捕获、异常的处理流程】、自定义异常类 )

接上次博客&#xff1a;Java学习&#xff08;12&#xff09;&#xff08;String类、String的查找方法、字符串转化、 替换、拆分、截取、trim方法、字符串的不可变性、StringBuilder和StringBuffer&#xff09;_di-Dora的博客-CSDN博客 目录 异常的概念 异常的体系结构 异常…

【Python基础知识点总结】

Python基础知识点总结 思维导图基础数据类型数据结构基础语法高级语法简单编程题工程项目类石头剪子布扑克发牌学生成绩管理系统 思维导图 基础数据类型 布尔(bool) True False字符(str) ‘hello Python’整型(int) -1,5,88浮点(float) -2.3,4.1 数据结构 字典 {“position”…

springboot+vue交流互动系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的交流互动系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风歌&a…

Springmvc练习二

1、网站练习&#xff0c;先清楚原理&#xff0c;便于拓展 注意一点就是页面定位的问题&#xff0c;如果你springmvc文件没有配置加上后缀“.jsp”的设置记得在网站控制器源代码的基础上加上“.jsp” 2、简单尝试一下就知道&#xff0c;这里所谓的参数绑定无非就是在java代码的…

【ChatGPT】ChatGPT国内镜像网站集合

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 什么是ChatGPT镜像&#xff1f; 亲测&#xff1a; 一、二狗问答(AI对话) 二、AiDuTu 三、WOChat 四、ChatGPT(个人感觉最好用) 我们可以利用ChatGPT干什么&#xff1f; 一、三分…

Java EE 初阶---多线程(二)

目录 四、多线程案例之--单例模式 4.1 单例模式 4.2 怎么去设计一个单例&#xff1f; 饿汉模式 懒汉模式 4.3 两种模式的总结 四、多线程案例之--单例模式 4.1 单例模式 是校招中最常考的设计模式之一. 啥是设计模式&#xff1f; 设计模式好比象棋中的 " 棋谱 "…

MaterialDesignInXamlToolkit 初学项目实战(1)首页搭建

前言 最近在学WPF&#xff0c;由于人比较烂&#xff0c;有一个星期没怎么动代码了。感觉有点堕落。现在开始记录WPF项目&#xff0c;使用MaterialDesignInXamlToolkit。 环境搭建 如果没下载MaterialDesign 的源码 github源码运行 在Nuget里面引入MaterialDesign Materia…

【ChatGPT镜像网站+MindShow高效生成PPT,保姆级安装教程】

&#x1f680; AI破局先行者 &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#x1f3c6;&am…

一、基础算法9:区间合并 模板题+算法模板(区间合并)

文章目录 算法模板离散化题目模板 模板题区间和原题链接题目题解思路 算法模板 离散化题目模板 // 将所有存在交集的区间合并 void merge(vector<PII> &segs) {vector<PII> res;sort(segs.begin(), segs.end());int st -2e9, ed -2e9;for (auto seg : segs…

SD-MTSP:遗传算法GA求解单仓库多旅行商问题(提供MATLAB代码,可以修改旅行商个数及起点)

一、单仓库多旅行商问题 多旅行商问题&#xff08;Multiple Traveling Salesman Problem, MTSP&#xff09;是著名的旅行商问题&#xff08;Traveling Salesman Problem, TSP&#xff09;的延伸&#xff0c;多旅行商问题定义为&#xff1a;给定一个&#x1d45b;座城市的城市集…

SpringSecurity和Shiro---权限设置

在 Web 开发中&#xff0c;安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求&#xff0c;但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题&#xff0c;就可能陷入一个两难的境地&#xff1a;一方面&#xff0c;应用存在严重的安全漏洞…

15-JavaScript-内部JS、外部JS、数据类型、关键词

1、内部JS&#xff1a;是在HTML文件中直接嵌入JavaScript代码的一种方式。使用<script>标签来定义JavaScript代码块。通常情况下&#xff0c;我们会将JavaScript代码放在文档的<head>或<body>标签内。 <!DOCTYPE html> <html> <head><…

MySQL-----事务管理

文章目录 前言一、什么是事务二、为什么会出现事务三、事物的版本支持四、事物的提交方式五、事务常见的操作方式六、事务隔离级别如何理解隔离性1隔离级别查看与设置隔离性读未提交【Read Uncommitted】读提交【Read Committed】可重复读【Repeatable Read】串行化【serializa…

ChatGPT 联网和插件功能,下周起可直接使用,无需排队!

夕小瑶科技说 分享 来源 | 新智元 OpenAI和谷歌&#xff0c;已经打得急红了眼&#xff0c;ChatGPT Plus用户&#xff0c;下周就可以体验联网和插件功能&#xff0c;无需再排队。鲨疯了&#xff0c;真的鲨疯了&#xff01; ChatGPT&#xff0c;下周开始联网&#xff0c;并开放插…

DAY 57 MySQL数据库的事务

事务的概念 事务是一种机制、一个操作序列&#xff0c;包含了一组数据库操作命令&#xff0c;并且把所有的命令作为一个 整体一起向系统提交或撤销操作请求&#xff0c;即这一组数据库命令要么都执行&#xff0c;要么都不执行。事务是一个不可分割的工作逻辑单元&#xff0c;在…