广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言编程数据结构带头双向循环链表全面详解
  • 548
分享到

C语言编程数据结构带头双向循环链表全面详解

2024-04-02 19:04:59 548人浏览 安东尼
摘要

目录前言一、什么是带头循环双向链表二、链表初始化三、链表接口函数1.尾插2.头插3.头删4.尾删5.任意位置插入数据6.任意位置删除数据四、打印链表总结前言 上一篇数据结构专栏:C语

前言

上一篇数据结构专栏:C语言数据结构单链表接口函数全面讲解教程

我们介绍了单链表的各个接口函数,大家可能会发现单链表存在一些缺陷:比如它一个节点要存储数据+下一个节点地址,占用的空间要远多于顺序表;并且由于单链表是无法从后往前找的,如果你想进行尾删这样的操作,你必须从第一个节点往后找,你的时间复杂度一定是O(n)。

为了解决上面的一些缺陷,我们今天来介绍带头双向循环链表

一、什么是带头循环双向链表

在这里插入图片描述

这种链表会有一个哨兵位head节点指向d1,然后d1指向d2…这和单链表非常相似。
但和单链表最大的区别就是:这种链表的每个节点不仅会存储下一个节点地址而且会存储上一个节点的地址,然后尾节点会存储一个指向哨兵位head的地址,然后哨兵位head会存储一个指向尾结点的地址。
具体代码如下:


typedef int LTDataType;//万一以后需要改链表数据类型,可以直接在这里更改(int)
typedef struct Listnode
{
	struct ListNode*next;
	struct ListNode*prev;
	LTDataType data;
}ListNode;//结构体重命名

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、链表初始化

在这里插入图片描述

类似于上图的效果,刚开始创建只有一个节点,它储存的前地址和后地址都指向自己

代码如下(示例):


#include<stdlib.h>//malloc函数头文件
ListNode* BuyListNode(LTDataType x)//创建一个节点
{
	ListNode*newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}
ListNode* ListInit()//链表初始化
{
	ListNode*phead = BuyListNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

ps:这里ListInit函数用的是返回值的方法,你也可以用二级指针传参来进行初始化操作

三、链表接口函数

1.尾插

在这里插入图片描述

我们以上图为例,原先链表的head节点的前驱指向3,然后3的后驱指向head节点,那在3后面怎么进行尾插呢?由于head节点里存放了3节点的地址,所以我们可以直接找到3节点,找到之后怎么办?把head节点的前驱改成4节点地址,3节点后驱改为4节点地址,最后4节点后驱指向head节点。如下图:

在这里插入图片描述

代码如下(示例):


#include<assert.h>//assert函数头文件
void ListPushBack(ListNode*phead, LTDataType x)//尾插
{
    assert(phead);//对传过来的指针进行断言,因为你要进行尾插至少得有个头节点啊
    //如果传过来的是空指针会进行报错
	ListNode*tail = phead->prev;
	ListNode*newnode = BuyListNode(x);
	tail->next = newnode;
	newnode->prev = tail;
	newnode->data = phead;
	phead->prev = newnode;
}

2.头插

在这里插入图片描述

如上图,先要在head和d1之间进行头插,怎么操作?非常简单,思路和尾插一模一样
head的后驱指向newnode,newnode的前驱和后驱分别指向phead和d1,d1前驱指向newnode如下图:

在这里插入图片描述

代码如下(示例):


void ListPushFront(ListNode*phead,LTDataType x)
{
	assert(phead);
	ListNode*first = phead->next;
	ListNode*newnode = BuyListNode(x);
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

注意!!!这里是先定义了一个first来存放d1这个地址,如果不事先定义的话,phead->next = newnode;head不再存储d1地址,你就找不到d1了。当然了,如果你就是不想先定义一个first来存放d1地址也可以。怎么做呢?“先连后断”,newnode后驱先接上d1节点,然后你head节点后驱接上newnode。

3.头删

头删也是和前面两个类似的思想

在这里插入图片描述

头删也就是把d1节点删掉,我们定义2个指针分别指向d1和d2,然后把head节点后驱接指向d2,d2前驱指向head即可,如下图:

在这里插入图片描述

代码如下(示例):


void ListPopFront(ListNode*phead)
{
	assert(phead);
	ListNode*first = phead->next;
	ListNode*second = first->next;
	phead->next = second;
	second->prev = phead;
}

4.尾删

在这里插入图片描述

现在要删除d3这个节点,我们定义一个tail和prev指针分别指向d3和d2,然后把d2后驱接上head,head前驱接上d2即可,如下图:

在这里插入图片描述

代码如下(示例):


void ListPopBack(ListNode*phead)
{
	assert(phead);
	assert(phead->next != phead);//要进行尾删至少保证有一个节点可删(非head节点)
	ListNode*tail = phead->prev;//头节点前驱指向尾部
	ListNode*prev = tail->prev;//通过尾部得到d2地址
	prev->next = phead;//d2后驱head节点
	phead->prev = prev;//head前驱指向d2节点
}

5.任意位置插入数据

要在某个位置前插入数据,你需要先找到那个位置在哪里,我们先写一个查找函数

在这里插入图片描述

怎么个找法呢?很简单,定义一个cur指针,然后从d1开始遍历看有没有我们想要找的数据,遍历到head节点结束。
代码如下(示例):


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;//遍历完链表都没有找到就返回空指针
}

找到所需位置后就是进行,插入操作


void ListInsert(ListNode*pos, LTDataType x)
{
	assert(pos);
	ListNode*prev = pos->prev;
	ListNode*newnode = BuyListNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

两个函数一起调用也是很简单的,比如我现在要在链表里数据3的位置前插入300,下面两行代码即可完成两个函数的运用。


ListNode*pos = ListFind(plist, 3);
ListInsert(pos, 300);

ps:这里找到所需位置指针,你如果需要,也可以通过该指针对该位置的值进行修改,比如(返回的指针)->data=n

6.任意位置删除数据

在这里插入图片描述

现在要删除pos位置的数据,怎么操作?非常简单!定义一个prev指向pos前一个节点,定义一个next指向pos后一个节点,然后prev和next连起来即可,如图:

在这里插入图片描述

代码如下(示例):


void ListErase(ListNode*pos)//指定位置删除
{
	assert(pos);
	ListNode*prev = pos->prev;
	ListNode*next = pos->next;
	prev->next = next;
	next->prev = prev;
	free(pos);//prev和next连起来了,pos就可以被释放掉了
}

四、打印链表

在这里插入图片描述

以上图为例:要打印一个链表,head节点是不需要打印的,我们只需要打印存储实际数据的d1,d2,d3即可,定义一个变量cur,让它从d1开始遍历,到head节点结束即可。
代码如下(示例):


void ListPrint(ListNode*phead)
{
	ListNode*cur = phead->next;
	while (cur != phead)
	{
		printf("%d\n", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

总结

本文介绍了带头循环双向链表,包括其定义、各个接口函数、及其遍历打印。虽然是链表中最复杂的结构,但它的代码操作却是最简单的,希望通过今天的学习读者能有所收获~更多关于带头双向循环链表数据结构的资料请关注编程网其它相关文章!

--结束END--

本文标题: C语言编程数据结构带头双向循环链表全面详解

本文链接: https://www.lsjlt.com/news/155185.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言编程数据结构带头双向循环链表全面详解
    目录前言一、什么是带头循环双向链表二、链表初始化三、链表接口函数1.尾插2.头插3.头删4.尾删5.任意位置插入数据6.任意位置删除数据四、打印链表总结前言 上一篇数据结构专栏:C语...
    99+
    2022-11-12
  • C语言超详细讲解数据结构中双向带头循环链表
    目录一、概念二、必备工作2.1、创建双向链表结构2.2、初始化链表2.3、动态申请节点2.4、打印链表2.5、销毁链表三、主要功能3.1、在pos节点前插入数据尾插头插3.2、删除p...
    99+
    2022-11-13
  • C语言数据结构中双向带头循环链表怎么实现
    这篇文章主要讲解了“C语言数据结构中双向带头循环链表怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言数据结构中双向带头循环链表怎么实现”吧!一、概念来画张图总体回顾下:在我们学习...
    99+
    2023-06-30
  • C语言超详细讲解双向带头循环链表
    目录一、双向带头循环链表的结构二、双向带头循环链表的函数接口1. 申请结点2. 初识化3. 打印4. 尾插尾删5. 头插头删6. 查找7. 中间插入和删除8. 判空及求链表长度9. ...
    99+
    2023-02-14
    C语言双向带头循环链表 C语言带头循环链表 C语言循环链表
  • C语言详解如何实现带头双向循环链表
    目录创建链表存储结构创建结点链表的初始化双向链表的打印双向链表尾插双向链表尾删双向链表头插双向链表头删双向链表查找双向链表pos前插入结点双向链表删除pos位置的结点双向链表的销毁顺...
    99+
    2022-11-13
  • C语言数据结构之双链表&循环链表&静态链表详解
    目录单链表 VS 双链表双链表双链表的初始化(带头结点)双链表的插入双链表的删除双链表的遍历循环单链表循环双链表循环双链表的初始化循环双链表的插入循环双链表的删除静态链表什么是静态链...
    99+
    2022-11-13
  • C++零基础精通数据结构之带头双向循环链表
    目录与单链表的区别代码的实现接口节点的构造初始化链表开辟节点销毁链表打印链表尾插链表尾删链表头插链表头删链表查找链表链表pos位置的删除总结与单链表的区别 单向/双向 单向:只有一个...
    99+
    2022-11-13
  • C语言超详细介绍与实现线性表中的带头双向循环链表
    目录一、本章重点二、带头双向循环链表介绍2.1什么是带头双向循环链表?2.2最常用的两种链表结构三、带头双向循环链表常用接口实现 3.1结构体创建3.2带头双向循环链表的初始化 3....
    99+
    2022-11-13
  • C语言数据结构超详细讲解单向链表
    目录1.链表概况1.1 链表的概念及结构1.2 链表的分类2. 单向链表的实现2.1 SList.h(头文件的汇总,函数的声明)2.2 SList.c(函数的具体实现逻辑)2.2.1...
    99+
    2022-11-13
  • C语言数据结构之单向链表详解分析
    链表的概念:链表是一种动态存储分布的数据结构,由若干个同一结构类型的结点依次串连而成。 链表分为单向链表和双向链表。 链表变量一般用指针head表示,用来存放链表首结点的地址。 每个...
    99+
    2022-11-12
  • C语言数据结构单链表接口函数全面讲解教程
    目录前言一、链表的概念及结构1.概念二、链表的使用1.遍历整个链表2.尾插3.头插4.头删5.尾删6.任意位置插入数据7.任意位置删除数据后记前言 上一期数据结构专栏我们学习了顺序表...
    99+
    2022-11-12
  • C语言实例真题讲解数据结构中单向环形链表
    目录1、例题引入2、何为带环链表3、题解思路4、拓展问题目录 1、例题引入 链接直达: 环形链表 题目: 2、何为带环链表  正常的单链表每个节点顺次链接,最后一个节点指...
    99+
    2022-11-13
  • C语言编程简单却重要的数据结构顺序表全面讲解
    目录前言一、线性表定义二、顺序表实现1概念及结构2静态顺序表2.1实现顺序表接口,第一步要对顺序表进行初始化2.2对顺序表的增删查改的接口函数(以尾插为例)3动态顺序表3.1动态顺序...
    99+
    2022-11-12
  • C语言数据结构顺序表中的增删改(头插头删)教程示例详解
    目录头插操作头删操作小结头插操作 继上一章内容(C语言数据结构顺序表中的增删改教程示例详解),继续讲讲顺序表的基础操作。 和尾插不一样,尾插出手阔绰直接的开空间,咱头插能开吗?好像没...
    99+
    2022-11-13
  • C语言编程数据结构栈与队列的全面讲解示例教程
    目录一、栈的表示和实现1栈的概念和结构2栈的初始化3压栈(栈顶插入一个数据)4出栈(栈顶删除一个数据)5取栈顶元素6取栈顶元素7判断栈是否为空二、队列的表示和实现1队列的概念及结构2...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作