双向循环链表的删除、插入
双向循环链表
双向循环链表是一种特殊的链表结构,它结合了双向链表和循环链表的特点。在双向循环链表中,每个节点都有两个指针,一个指向前一个节点,另一个指向后一个节点,从而形成双向链接。同时,链表的头节点和尾节点相互链接,形成一个循环结构。
这种结构使得双向循环链表在遍历和操作上具有更高的灵活性。由于存在双向链接,可以从链表的任何节点开始向前或向后遍历。而循环结构则使得链表在到达尾部时可以自动回到头部,形成一个闭合的环,无需额外的处理即可实现循环遍历。
双向循环链表在实际应用中具有广泛的用途。例如,它可以用于实现循环队列、循环双向队列等数据结构,以支持循环访问和操作。此外,双向循环链表还可以用于实现某些特定的算法和数据结构,如约瑟夫环问题等。
需要注意的是,双向循环链表在插入和删除节点时需要考虑更多的边界条件和指针操作,因此相对于单向链表或简单的双向链表,其实现可能会更为复杂。然而,这种复杂性也带来了更高的灵活性和功能性,使得双向循环链表在某些特定场景下非常有用。
本文将展示双向循环链表的插入与删除(最后附上完整代码)。
双向循环链表头部插入
/*******************************************************************
*
* 函数名称: DoubleCirLList_HeadInsert
* 函数功能: 在双向循环链表头部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_HeadInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->next == Head->next && Head->next->prev==Phead)
{
break;
}
}
Phead->next=New;
New->prev=Phead;
New->next=Head->next;
Head->next->prev=New;
Head->next=New;
return true;
}
双向循环链表尾部插入
/*******************************************************************
*
* 函数名称: DoubleCirLList_TailInsert
* 函数功能: 在双向循环链表尾部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_TailInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->next == Head->next && Head->next->prev==Phead)
{
break;
}
}
New->prev=Phead;
Phead->next=New;
New->next=Head->next;
Head->next->prev=New;
return true;
}
双向循环链表指定部位插入
/*******************************************************************
*
* 函数名称: DoubleCirLList_DestInsert
* 函数功能: 在双向循环链表指定部位插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* @c :DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_DestInsert(DoubleLList_t *Head,DataType_t dest,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head->next;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
if(Phead->data==dest)
{
break;
}
}
if(Phead->next == NULL && Phead->data != dest)
{
printf("dest node is not found\n");
return false;
}
New->next=Phead->next;
Phead->next->prev=New;
Phead->next=New;
New->prev=Phead;
return true;
}
双向循环链表头部删除
/*******************************************************************
*
* 函数名称: DoubleCirLList_HeadDel
* 函数功能: 删除双向循环链表头部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_HeadDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head->next;
DoubleLList_t *Temp = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
}
Phead->next=Head->next->next;
Temp->next->prev=Phead;
Head->next=Head->next->next;
Temp->next=NULL;
Temp->prev=NULL;
free(Temp);
return true;
}
双向循环链表尾部删除
/*******************************************************************
*
* 函数名称: DoubleCirLList_TailDel
* 函数功能: 删除双向循环链表尾部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_TailDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head->next;
DoubleLList_t *Temp = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
}
Phead->prev->next=Head->next;
Phead->next=NULL;
Temp->prev=Phead->prev;
Phead->prev=NULL;
free(Phead);
return true;
}
双向循环链表指定部位删除
/*******************************************************************
*
* 函数名称: DoubleCirLList_DestDel
* 函数功能:: 删除双向循环链表指定部位结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b:DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_DestDel(DoubleLList_t *Head,DataType_t dest)
{
DoubleLList_t *Phead = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
if(Phead->data==dest)
{
break;
}
}
Phead->next->prev=Phead->prev;
Phead->prev->next=Phead->next;
Phead->next=NULL;
Phead->prev=NULL;
free(Phead);
return true;
}
完整代码
/*******************************************************************
*
* file name: DoubleCirLList.c
* author : m17872844806@163.com
* date : 2024/04/25
* function : 双向循环链表的插,删
* note : None
*
* CopyRight (c) 2023-2024 m17872844806@163.com All Right Reseverd
*
* *****************************************************************/
#include<stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//指的是双向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
//构造双向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct DoubleLinkedList
{
DataType_t data; //结点的数据域
struct DoubleLinkedList *prev; //直接前驱的指针域
struct DoubleLinkedList *next; //直接后继的指针域
}DoubleLList_t;
//创建一个空双向循环链表,空链表应该有一个头结点,对链表进行初始化
DoubleLList_t * DoubleCirLList_Create(void)
{
//1.创建一个头结点并对头结点申请内存
DoubleLList_t *Head = (DoubleLList_t *)calloc(1,sizeof(DoubleLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}
//2.对头结点进行初始化,头结点是不存储数据域,指针域指向自身即可,体现“循环”
Head->prev = Head;
Head->next = Head;
//3.把头结点的地址返回即可
return Head;
}
//创建新的结点,并对新结点进行初始化(数据域 + 指针域)
DoubleLList_t * DoubleCirLList_NewNode(DataType_t data)
{
//1.创建一个新结点并对新结点申请内存
DoubleLList_t *New = (DoubleLList_t *)calloc(1,sizeof(DoubleLList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is Failed");
return NULL;
}
//2.对新结点的数据域和指针域(2个)进行初始化,指针域指向结点自身,体现“循环”
New->data = data;
New->prev = New;
New->next = New;
return New;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_HeadInsert
* 函数功能: 在双向循环链表头部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_HeadInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->next == Head->next && Head->next->prev==Phead)
{
break;
}
}
Phead->next=New;
New->prev=Phead;
New->next=Head->next;
Head->next->prev=New;
Head->next=New;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_TailInsert
* 函数功能: 在双向循环链表尾部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_TailInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->next == Head->next && Head->next->prev==Phead)
{
break;
}
}
New->prev=Phead;
Phead->next=New;
New->next=Head->next;
Head->next->prev=New;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_DestInsert
* 函数功能: 在双向循环链表指定部位插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* @c:DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_DestInsert(DoubleLList_t *Head,DataType_t dest,DataType_t data)
{
DoubleLList_t *New = DoubleCirLList_NewNode(data);
DoubleLList_t *Phead = Head->next;
if (Head->next == Head)
{
Head->next=New;
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
if(Phead->data==dest)
{
break;
}
}
if(Phead->next == NULL && Phead->data != dest)
{
printf("dest node is not found\n");
return false;
}
New->next=Phead->next;
Phead->next->prev=New;
Phead->next=New;
New->prev=Phead;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_HeadDel
* 函数功能: 删除双向循环链表头部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_HeadDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head->next;
DoubleLList_t *Temp = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
}
Phead->next=Head->next->next;
Temp->next->prev=Phead;
Head->next=Head->next->next;
Temp->next=NULL;
Temp->prev=NULL;
free(Temp);
return true;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_TailDel
* 函数功能: 删除双向循环链表尾部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_TailDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head->next;
DoubleLList_t *Temp = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
}
Phead->prev->next=Head->next;
Phead->next=NULL;
Temp->prev=Phead->prev;
Phead->prev=NULL;
free(Phead);
return true;
}
/*******************************************************************
*
* 函数名称: DoubleCirLList_DestDel
* 函数功能: 删除双向循环链表指定部位结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b:DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleCirLList_DestDel(DoubleLList_t *Head,DataType_t dest)
{
DoubleLList_t *Phead = Head->next;
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return true;
}
while(Phead->next!=Head->next)
{
Phead=Phead->next;
if(Phead->data==dest)
{
break;
}
}
Phead->next->prev=Phead->prev;
Phead->prev->next=Phead->next;
Phead->next=NULL;
Phead->prev=NULL;
free(Phead);
return true;
}
//遍历链表
bool DoubleCirLList_Print(DoubleLList_t *Head)
{
//对单向循环链表的头结点的地址进行备份
DoubleLList_t *Phead = Head;
//判断当前链表是否为空,为空则直接退出
if (Head->next == Head)
{
printf("current linkeflist is empty!\n");
return false;
}
//从首结点开始遍历
while(Phead->next)
{
//把头结点的直接后继作为新的头结点
Phead = Phead->next;
//输出头结点的直接后继的数据域
printf("data = %d\n",Phead->data);
//判断是否到达尾结点,尾结点的next指针是指向首结点的地址
if (Phead->next == Head->next && Head->next->prev==Phead)
{
break;
}
}
return true;
}
int main(int argc, char const *argv[])
{
DoubleLList_t *phe=DoubleCirLList_Create();
DoubleCirLList_HeadInsert(phe,20);
DoubleCirLList_HeadInsert(phe,10);
DoubleCirLList_TailInsert(phe,30);
DoubleCirLList_TailInsert(phe,50);
DoubleCirLList_DestInsert(phe,30,40);
DoubleCirLList_HeadDel(phe);
DoubleCirLList_TailDel(phe);
DoubleCirLList_DestDel(phe,40);
DoubleCirLList_Print(phe);
return 0;
}
该代码成功运行后,可以在终端肯定data的值为20,30,代码可供各位惨考移植。
如果该程序双向循环链表的代码有什么问题,请将问题发至网易邮箱 m17872844806@163.com,作者将及时改正,欢迎各位老爷提出意见。
麻烦三连加关注!!!!
比心!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律