读者可以先阅读这一篇:数据结构——单链表的增加、删除、查找、修改,详细解析_昵称就是昵称吧的博客-优快云博客,可以更好的理解带头双向循环链表。
目录
一、带头双向循环链表的处理和介绍
1、带头双向循环链表的概念
链表的概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
带头双向循环链表是链表中最复杂的,因为它具有了链表存在的结构中所有的结构:带头,双向和循环。
1、带头和不带头:带头就是链表带有头节点,这个头节点只具有哨兵位的作用,意思就是它不随着链表的改变而改变,定义之后就固定不变了,并且头节点里面不存放数据;不带头就是链表没有头节点。
2、双向和单项:双向就是一个节点,既存上一个节点的地址,也存下一个节点的地址;单向就是一个节点,只存下一个节点的地址。
3、循环和非循环:循环就是这个链表的最后一个节点里的指针存放的地址,如果链表带头,就存放的头节点的地址;如果链表不带头,就存放第一个节点的地址;非循环就是这个链表的最后一个节点存放的地址是空的。
2、带头双向循环链表的结构
头节点里面是不存放数据的,只具有哨兵位的作用,各个节点之间通过节点里面的指针进行链接。单向链表里面,每个节点里只有一个指针,因为只需要指向下一个节点;但是双向链表中,每个节点里有两个指针,一个指向上一个节点,一个指向下一个节点。
3、节点的处理
因为双向链表里面每个节点,都会存储一个数据和两个指针prev和next,指针prev指向上一个节点,指针next指向下一个节点,所以用结构体来表示节点。
typedef int ListDataType;//类型名重定义
typedef struct ListNode
{
struct ListNode* prev;
struct ListNode* next;
ListDataType data;
}ListNode;
4、头节点的处理
在这里,我们用指针phead/plist表示头节点的地址,因为是带有头双向循环链表,所以定义头节点的时候,其节点里的指针prev和next都必须指向自己。
phead->prev = phead;//头节点不存放数据
phead->next = phead;
5、节点(结构体)内存空间的开辟
因为每个节点都是结构体,为了不会导致内存空间的浪费,需要用一个节点,就开辟一个节点。所以用动态内存开辟函数malloc即可,每次开辟一个结构体大小的内存空间。但是要注意,每个节点创建的时候,其里面的指针prev和next都要先置为空指针,方便后面的修改。
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->next = NULL;//因为是新节点,都先初始化置为空指针
newnode->prev = NULL;
newnode->data = x;//将想要的数据放入进去
二、链表的主体框架
1、整体框架
int main()
{
int input = 0;
do
{
meun();
printf("请输入想要进行的操作:");
scanf("%d", &input);
switch (input)
{
case 1:
{