双链表(双向带头循环链表)

双向链表

双向链表也叫双链表,是链表中的一种。它的每个数据结点中都有两个指针,分别指向直接前驱和直接后继,所以从链表的任意一个结点都可以很方便的访问到它的前驱结点和后继结点,一般我们都构造双向循环链表。
## 带头结点和不带头结点   其实这个带头结点和不带头结点在单链表那篇博客中就应该提的,但是我放在这里,原因是,本篇主要介绍带头结点的双向循环链表。在这里结合例子介绍会更加清楚一些。
那么带头结点和不带头结点的区别在哪里呢?

带头结点:head-->p1-->p2-->p3-->p4..........

不带头结点:p1-->p2-->-->p3-->p4.............

如果是环的话带头结点和不带头结点是下面这样的

带头结点:head-->p1-->p2-->p3-->head-->p1..........

不带头结点:p1-->p2-->-->p3-->p1-->p2.............

图解如下: ![这里写图片描述](https://img-blog.csdn.net/20180916204310258?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNTUwMDE4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
头结点直接指向链表的首元素,有助于我们直接找到链表的第一个元素,带头结点的链表的第一个元素其实就是head->next元素,头结点只是给我们提供了一个入口,方便我们快速找到第一个元素。当然,头结点的位置是不能变的,不能变主要体现在头插和头删的时候,如果要在带头结点的链表中头插一个元素,那么一定是插在头结点后面的位置的,而不是在头结点前面插。
##双向带头循环链表 >顾名思义,这是一个双链表,而且带头结点,还是个环。那么本篇的重点是讨论这一类常见的链表的插入和删除。

首先需要顶一个双链表,前面说了,双链表的每个数据结点中有两个指针,分别指向前驱结点和后继结点。
※※※再次声明,以下所有操作均为双向带头循环链表

双链表的定义

//双链表的定义
typedef   int  datatype;
typedef  struct DNode{
	datatype   data;//数据域
	DNode * prev;//指向前驱结点
	DNode *next;//指向后继结点
}Dlist;

###创建结点

//创建结点
Dlist *CreateNode(datatype  data)
{
	Dlist *node = (Dlist*)malloc(sizeof(Dlist));
	node->data = data;
	node->next = node->prev = NULL;//创建的新结点前驱和后继都为空
	return node;
}

###初始化

//初始化
void DListInit(Dlist **ps)
{
	assert(ps);
	Dlist *node = CreateNode(0);//这里0是无效的,因为在头结点中
	node->next = node->prev = node;//构成环,所以创建的这个结点前驱和后继都是本身
	*ps = node;//将创建好的结点放入链表中

}

这里写图片描述
###打印链表

//打印链表
void DListPrint(Dlist *head)
{
	Dlist *cur = head->next;
	for (cur = head->next; cur != head; cur = cur->next)
	{
		printf("%d-->", cur->data);
	}
	printf("\n");
}

###清空

//清空链表
void ClearDList(Dlist *head)
{
	Dlist *cur=head->next;
	Dlist *next;
	while (cur != head)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	head->prev = head->next = head;//清空完后只剩头结点
}

###销毁

//销毁
void DestoryDList(Dlist *head)
{
	ClearDList(head);
	free(head);
}

###头插

//头插,插在头结点后面
void  PushFront(Dlist *head,datatype data)
{
	Dlist *node = CreateNode(data);
	node->next = head->next;
	head->next->prev = node;
	node->prev = head;
	head->next = node;
}

这里写图片描述
这里写图片描述
###尾插
这里写图片描述

//尾插
void PushBack(Dlist *head, datatype data)
{
	Dlist *node = CreateNode(data);
	node->prev = head->prev;
	head->prev->next = node;
	node->next = head;
	head->prev = node;
}

这里写图片描述
###任意结点插入

//插入到指定位置
void Insert(Dlist *head,Dlist *pos,datatype data)
{
	Dlist *node = CreateNode(data);
	node->next = pos;
	node->prev = pos->prev;
	pos->prev->next = node;
	pos->prev = node;
}

这里写图片描述
###头删

//头删
void PopFront(Dlist *head)
{
	Dlist *del = head->next;
	head->next = del->next;
	del->next->prev = head;
}

这里写图片描述
###尾删

//尾删
void PopBack(Dlist *head)
{
	Dlist *del = head->prev;
	del->prev->next = head;
	head->prev = del->prev;
	free(del);
}

这里写图片描述

###删除任意结点

//删除任意位置的结点
void DListerase(Dlist *head, Dlist *pos)
{
	assert(head->next != head);
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
}

这里写图片描述
上一篇:单链表https://blog.csdn.net/qq_40550018/article/details/82687292
如有纰漏请路过的大神指正!!!

猜你喜欢

转载自blog.csdn.net/qq_40550018/article/details/82728448