【图解】(数据结构)带头双向循环链表,一篇教你学会!

前言

❤️ 铁子们大家好,欢迎大家来到出小月的博客里,今天给大家带来的是【数据结构】之带头双向循环链表的增、删、查、改,这可是很重要的东西哦❗
希望大家看完我这篇文章都能够“涨芝士”,感觉小月写的还不错的话,记得👍🏻点赞加关注😘鼓励一下博主哦,不然下次可找不到我啦❗❗

作者介绍

❤️作者的gitee:出小月
❤️ 作者的主页:出小月的《程序员历险记》
❤️专栏:《数据结构初级》
❤️跟大家分享一勺鸡汤:请做足够多的努力,让自己有足够多的选择,让我们一起干了这碗鸡汤


一、双向带头循环链表

上一篇呢我们说了无头单向非循环链表,它有什么特点呢?
它的结构简单,一般不会单独存储数据,实际中更多作为其他数据结构的子结构。

在这里插入图片描述

今天我们来说,带头双向循环链表,它呢,结构最复杂🤨🤨,虽然结构很复杂,但是使用代码实现以后会发现结构带来了很多优势😍😍,反而容易实现,后面我们实现代码就知道啦❗❗

🤨🤨就比如说,之前我们单链表需要删除最后一个元素时,是不是得找到前一个元素,然后把最后一个元素删除,还得把指向前一个元素的指针指向空。但是前一个元素怎么找呢❓❓这是一个问题,于是我们用了前后指针,但是如果用了这个双向的链表,我就不用从头遍历了,直接就找到了❗❗❗

在这里插入图片描述

二、具体实现

1.结构

typedef double dldatatype;
typedef struct dlist
{
	struct  dlist* next;
	struct  dlist* prev;
	dldatatype data;
}dlist;

2.初始化链表

dlist* dlistinit()
{
dlist*	dl = createnode(0);
dl->next = dl;
dl->prev = dl;
return dl;
}

3、产生一个新节点

dlist* createnode(dldatatype x)
{
	dlist* newnode = (dlist*)malloc(sizeof(dlist));
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

4、头插数据

思路:😁用next记住原来的首元结点,让新节点成为新的首元结点,新节点的next值是next;

void dlistpushfront(dlist* dl, dldatatype x)
{
	assert(dl);
	dlist* next = dl->next;
	dlist* newnode = createnode(x);
	dl->next = newnode;
	newnode->prev = dl;
	newnode->next = next;
	next->prev = newnode;
}

在这里插入图片描述

5、尾插数据

思路:👍👍尾结点的的下一个值是新节点,这个新节点就是插入后的尾结点

void dlistpushback(dlist* dl, dldatatype x)
{
	assert(dl);
	dlist* tail = dl->prev;
	dlist* newnode = createnode(x);
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = dl;
	dl->prev = newnode;
}

在这里插入图片描述

6、头删数据

思路:🤗要删除首元结点,首先记住首元结点的下一个值next,然后让头节点的下一个值置为next(原来首元结点的下一个结点);

void dlistpopfront(dlist* dl)
{
	assert(dl);
	dlist* cur = dl->next;
	dlist* next = cur->next;
	free(cur);
	dl->next = next;
	next->prev = dl;
}

在这里插入图片描述

7、尾删数据

思路:🎶🎶删除尾结点,把原来尾节点的前一个值,置为现在的尾结点

void dlistpopback(dlist* dl)
{
	assert(dl);
	dlist* tail = dl->prev;
	dlist* prev = tail->prev;
	free(tail);
	prev->next = dl;
	dl->prev = prev;
}

在这里插入图片描述

8、找到任意值的位置

dlist* findval(dlist* dl, dldatatype x)
{
	dlist* cur = dl;
	while (cur)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

9、在任意值前插入

void dlistinsert(dlist* dl, dlist* pos, dldatatype x)
{
	dlist* prev = pos->prev;
	dlist* newnode = createnode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

10、删除任意值

void dlistdelete(dlist* dl, dlist* pos)
{
	dlist* prev = pos->prev;
	dlist* next = pos->next;
	free(pos);
	prev->next = next;
	next->prev = prev;
}

11、打印链表

void printdlist(dlist* dl)
{
	dlist* cur = dl->next;
	while (cur!=dl)
	{
		printf("%d", cur->data);
		cur = cur->next;
	}
}

今天就分享到这里了,友友们看都看到这里了记得点赞👍👍🤗加关注哦!!!有什么不懂的地方可以私信博主哦!

  • 19
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

出小月(充电停更版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值