【双向循环链表_C语言】创建头结点和新结点、插入新结点、删除结点、遍历链表 - 实践

目录

双向循环链表概述

定义结点类型

创建头结点

创建新结点

插入新结点

头部插入

尾部插入

指定插入

遍历

删除结点

删除头结点

尾部删除

指定删除

全部代码


双向循环链表概述

  1. 双向循环链表的每个结点都有两个指针:一个指向前一个结点,另一个指向后一个结点。
  2. 链表的尾结点的下一个指针指向头结点,而头结点的前一个指针指向尾结点,从而形成一个闭环。

定义结点类型

创建一个结构体用于定义结点类型,结构体成员包括数据域、直接前驱、直接后继。

typedef int DataType_t;//起别名,增加可移植性
typedef struct DoubleCircList//结点的结构体类型
{
DataType_t data;
struct DoubleCircList *next;//结点的后继指针next
struct DoubleCircList *prev;//结点的前驱指针prev
}DoublecirL_t;

创建头结点

为了体现循环,创建新的双向循环链表时,头结点的next指针指向自身的地址,prev指针也指向自身的地址。

//创建一个头结点,头结点的next指针指向自身,prev指针指向自身
DoublecirL_t* DoubleCircList_Creat()
{
DoublecirL_t* Head = (DoublecirL_t*)calloc(1,sizeof(DoublecirL_t));
if(NULL == Head)
{
perror("calloc heap Head memory is failed");
exit(-1);
}
Head->next = Head;
Head->prev = Head;
return Head;
}

创建新结点

创建新结点时,结点未与其他结点连接,所以next指针指向自身的地址,prev指针也指向自身的地址。

//创建新结点
DoublecirL_t* DoubleCircList_NewNode(DataType_t data)
{
DoublecirL_t* New = (DoublecirL_t*)calloc(1,sizeof(DoublecirL_t));
if(NULL == New)
{
perror("calloc heap New node memory is failed");
return NULL;
}
New->data = data;
New->next = New;
New->prev = New;
return New;
}

插入新结点

头部插入

两种情况:

  1. 当前链表只有头结点。
  2. 当前链表有多个结点。

//头部插入
bool DoubleCircList_HeadAdd(DoublecirL_t* Head,DataType_t data)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
//判断链表是否为空,为空则直接插入新结点
if(Head->next == Head)
{
Head->next = New;
return true;
}
DoublecirL_t* Phead = Head->next;//Phead == 首结点
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
New->next = Head->next;
New->prev = Phead;
Head->next->prev = New;
Phead->next = New;
Head->next = New;
return true;
}

尾部插入

两种情况:

  1. 当前链表只有头结点。
  2. 当前链表有多个结点。
bool DoubleCircList_TailAdd(DoublecirL_t* Head,DataType_t data)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
//判断链表是否为空,为空则直接插入新结点
if(Head->next == Head)
{
Head->next = New;
return true;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
New->next = Head->next;//新结点的next指针指向首结点
New->prev = Phead;//新结点的prev指针指向尾结点
Head->next->prev = New;//首结点的prev指针指向New
Phead->next = New;//尾结点的next指针指向New
return true;
}

指定插入

//指定插入
bool DoubleCircList_DestAdd(DoublecirL_t* Head,DataType_t data,DataType_t destval)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->data != destval && Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead->data != destval)//如果当前Phead不等于目标值,说明遍历完成且没找到目标值
{
perror("can not find to destval");
return false;
}
//如果找到目标值
//如果目标值是尾结点
if(Phead->next == Head->next)
{
New->next = Head->next;//新结点的next指针指向首结点的地址
New->prev = Phead;//新结点的prev指针指向Phead
Head->next->prev = New;//首结点的prev指针指向新结点
Phead->next = New;//尾结点的指针指向新结点
return true;
}
//目标值找到且不在尾结点
New->next = Phead->next;//新结点的next指针指向Phead直接后继的地址
New->prev = Phead;//新结点的prev指针指向Phead的直接前驱
Phead->next->prev = New;//Phead的直接后继的prev指针指向新结点
Phead->next = New;//Phead的next指针指向新结点
return true;
}

遍历

//遍历
bool DoubleCircList_Print(DoublecirL_t* Head)
{
if(Head->next == Head)
{
perror("DoubleCircList is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next)
{
printf("%d\n",Phead->data);
if(Phead->next == Head->next)
{
break;
}
Phead = Phead->next;
}
}

删除结点

删除头结点

先要判断链表是否为空。

//头部删除
bool DoubleCircList_HeadDel(DoublecirL_t* Head)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next)//如果整个链表只有头结点和首结点
{
DoublecirL_t* p = Head->next;
Head->next->next = NULL;
Head->next->prev = NULL;
Head->next = Head;//头结点的next指针指向自身
free(p);
return true;
}
DoublecirL_t* p = Head->next;//
Phead->next = Head->next->next;//尾结点的next指针指向首结点的直接后继的地址
Head->next->next->prev = Phead;//首结点的直接后继的prev指针指向尾结点
Head->next = Head->next->next;//头结点的next指针指向首结点的直接后继的地址
p->next = NULL;
p->prev = NULL;
free(p);
return true;
}

尾部删除

//尾部删除
bool DoubleCircList_TailDel(DoublecirL_t* Head)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next)//如果整个链表只有头结点和首结点
{
DoublecirL_t* p = Head->next;
Head->next->next = NULL;
Head->next->prev = NULL;
Head->next = Head;//头结点的next指针指向自身
free(p);
return true;
}
Head->next->prev = Phead->prev;//首结点的prev指针指向Phead的直接前驱
Phead->prev->next = Head->next;//尾结点的直接前驱的next指针指向首结点
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}

指定删除

//指定删除
bool DoubleCircList_DestDel(DoublecirL_t *Head,DataType_t destval)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->data != destval && Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next && Phead->data == destval)//如果目标值是首结点
{
DoublecirL_t* p = Head->next;
while(p->next != Head->next)
{
p = p->next;
}
DoublecirL_t* backups = Head->next;
p->next = Head->next->next;//尾结点的next指针指向首结点的直接后继
Head->next->next->prev = p;//首结点的直接后继的prev指针指向尾结点
Head->next = Head->next->next;//头结点的next指针指向首结点的直接后继
backups->next = NULL;
backups->prev = NULL;
free(backups);
return true;
}
if (Phead->next == Head->next && Phead->data == destval)//如果尾结点正好是目标值,尾删
{
Head->next->prev = Phead->prev;//首结点的prev指针指向尾结点的直接前驱
Phead->prev->next = Head->next;//尾结点的直接前驱的next指针指向首结点
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}
if (Phead->next == Head->next && Phead->data != destval)//如果已经遍历到尾结点并且没有找到目标值,则直接退出
{
perror("can not find to destval in DoubleCircListct");
return false;
}
//中间删除
Phead->prev->next = Phead->next;//Phead的直接前驱的next指针指向Phead的直接后继
Phead->next->prev = Phead->prev;//Phead的直接后继的prev指针指向Phead的直接前驱
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}

全部代码

#include
#include
#include
typedef int DataType_t;//起别名,增加可移植性
typedef struct DoubleCircList//结点的结构体类型
{
DataType_t data;
struct DoubleCircList *next;//结点的后继指针next
struct DoubleCircList *prev;//结点的前驱指针prev
}DoublecirL_t;
//创建一个头结点,头结点的next指针指向自身,prev指针指向自身
DoublecirL_t* DoubleCircList_Creat()
{
DoublecirL_t* Head = (DoublecirL_t*)calloc(1,sizeof(DoublecirL_t));
if(NULL == Head)
{
perror("calloc heap Head memory is failed");
exit(-1);
}
Head->next = Head;
Head->prev = Head;
return Head;
}
//创建新结点
DoublecirL_t* DoubleCircList_NewNode(DataType_t data)
{
DoublecirL_t* New = (DoublecirL_t*)calloc(1,sizeof(DoublecirL_t));
if(NULL == New)
{
perror("calloc heap New node memory is failed");
return NULL;
}
New->data = data;
New->next = New;
New->prev = New;
return New;
}
//头部插入
bool DoubleCircList_HeadAdd(DoublecirL_t* Head,DataType_t data)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
//判断链表是否为空,为空则直接插入新结点
if(Head->next == Head)
{
Head->next = New;
return true;
}
DoublecirL_t* Phead = Head->next;//Phead == 首结点
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
New->next = Head->next;
New->prev = Phead;
Head->next->prev = New;
Phead->next = New;
Head->next = New;
return true;
}
//尾部插入
bool DoubleCircList_TailAdd(DoublecirL_t* Head,DataType_t data)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
//判断链表是否为空,为空则直接插入新结点
if(Head->next == Head)
{
Head->next = New;
return true;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
New->next = Head->next;//新结点的next指针指向首结点
New->prev = Phead;//新结点的prev指针指向尾结点
Head->next->prev = New;//首结点的prev指针指向New
Phead->next = New;//尾结点的next指针指向New
return true;
}
//指定插入
bool DoubleCircList_DestAdd(DoublecirL_t* Head,DataType_t data,DataType_t destval)
{
DoublecirL_t* New = DoubleCircList_NewNode(data);
if(NULL == New)
{
perror("can not insert new node");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->data != destval && Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead->data != destval)//如果当前Phead不等于目标值,说明遍历完成且没找到目标值
{
perror("can not find to destval");
return false;
}
//如果找到目标值
//如果目标值是尾结点
if(Phead->next == Head->next)
{
New->next = Head->next;//新结点的next指针指向首结点的地址
New->prev = Phead;//新结点的prev指针指向Phead
Head->next->prev = New;//首结点的prev指针指向新结点
Phead->next = New;//尾结点的指针指向新结点
return true;
}
//目标值找到且不在尾结点
New->next = Phead->next;//新结点的next指针指向Phead直接后继的地址
New->prev = Phead;//新结点的prev指针指向Phead的直接前驱
Phead->next->prev = New;//Phead的直接后继的prev指针指向新结点
Phead->next = New;//Phead的next指针指向新结点
return true;
}
//遍历
bool DoubleCircList_Print(DoublecirL_t* Head)
{
if(Head->next == Head)
{
perror("DoubleCircList is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next)
{
printf("%d\n",Phead->data);
if(Phead->next == Head->next)
{
break;
}
Phead = Phead->next;
}
}
//头部删除
bool DoubleCircList_HeadDel(DoublecirL_t* Head)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next)//如果整个链表只有头结点和首结点
{
DoublecirL_t* p = Head->next;
Head->next->next = NULL;
Head->next->prev = NULL;
Head->next = Head;//头结点的next指针指向自身
free(p);
return true;
}
DoublecirL_t* p = Head->next;//
Phead->next = Head->next->next;//尾结点的next指针指向首结点的直接后继的地址
Head->next->next->prev = Phead;//首结点的直接后继的prev指针指向尾结点
Head->next = Head->next->next;//头结点的next指针指向首结点的直接后继的地址
p->next = NULL;
p->prev = NULL;
free(p);
return true;
}
//尾部删除
bool DoubleCircList_TailDel(DoublecirL_t* Head)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next)//如果整个链表只有头结点和首结点
{
DoublecirL_t* p = Head->next;
Head->next->next = NULL;
Head->next->prev = NULL;
Head->next = Head;//头结点的next指针指向自身
free(p);
return true;
}
Head->next->prev = Phead->prev;//首结点的prev指针指向Phead的直接前驱
Phead->prev->next = Head->next;//尾结点的直接前驱的next指针指向首结点
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}
//指定删除
bool DoubleCircList_DestDel(DoublecirL_t *Head,DataType_t destval)
{
//判断链表是否为空,为空则直接退出
if(Head->next == Head)
{
perror("DoubleCircListct is empty");
return false;
}
DoublecirL_t* Phead = Head->next;
while(Phead->data != destval && Phead->next != Head->next)
{
Phead = Phead->next;
}
if(Phead == Head->next && Phead->data == destval)//如果目标值是首结点
{
DoublecirL_t* p = Head->next;
while(p->next != Head->next)
{
p = p->next;
}
DoublecirL_t* backups = Head->next;
p->next = Head->next->next;//尾结点的next指针指向首结点的直接后继
Head->next->next->prev = p;//首结点的直接后继的prev指针指向尾结点
Head->next = Head->next->next;//头结点的next指针指向首结点的直接后继
backups->next = NULL;
backups->prev = NULL;
free(backups);
return true;
}
if (Phead->next == Head->next && Phead->data == destval)//如果尾结点正好是目标值,尾删
{
Head->next->prev = Phead->prev;//首结点的prev指针指向尾结点的直接前驱
Phead->prev->next = Head->next;//尾结点的直接前驱的next指针指向首结点
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}
if (Phead->next == Head->next && Phead->data != destval)//如果已经遍历到尾结点并且没有找到目标值,则直接退出
{
perror("can not find to destval in DoubleCircListct");
return false;
}
//中间删除
Phead->prev->next = Phead->next;//Phead的直接前驱的next指针指向Phead的直接后继
Phead->next->prev = Phead->prev;//Phead的直接后继的prev指针指向Phead的直接前驱
Phead->next = NULL;
Phead->prev = NULL;
free(Phead);
return true;
}
int main(int argc, char const *argv[])
{
DoublecirL_t* Head = DoubleCircList_Creat();
DoubleCircList_HeadAdd(Head,3);
DoubleCircList_HeadAdd(Head,8);
DoubleCircList_TailAdd(Head,2);
DoubleCircList_TailAdd(Head,9);
DoubleCircList_DestAdd(Head,1,9);
DoubleCircList_Print(Head);//8 3 2 9 1
printf("\n");
DoubleCircList_HeadDel(Head);
DoubleCircList_TailDel(Head);
DoubleCircList_DestDel(Head,2);
DoubleCircList_Print(Head);//3 9
return 0;
}

执行结果:

posted @ 2025-08-11 10:06  yfceshi  阅读(8)  评论(0)    收藏  举报