双向链表的插入、删除
双向链表
双向链表(Doubly Linked List)是一种更复杂的链表结构,它允许链表中的节点在两个方向上链接。在双向链表中,每个节点包含两个链接:一个指向前一个节点(如果它不是第一个节点的话),另一个指向下一个节点(如果它不是最后一个节点的话)。此外,每个节点还包含一个数据元素。
这种结构提供了更高的灵活性,因为它允许我们从链表的任何一端开始遍历,或者在链表中的任何位置进行插入和删除操作。然而,这种灵活性也带来了更高的复杂性,因为每个节点都需要存储两个链接而不是一个。
双向链表的主要优点是它可以向前和向后遍历。这使得双向链表在需要频繁进行插入和删除操作的情况下非常有用,特别是在链表的中间部分。然而,由于每个节点都需要额外的空间来存储链接,所以双向链表在内存使用上可能不如单向链表高效。
在实际应用中,双向链表常用于实现一些需要双向遍历的数据结构,如撤销/重做操作、双向队列等。
本文将展示双向链表的插入与删除(最后附上完整代码)。
双向链表头部插入
/*******************************************************************
*
* 函数名称: DoubleLList_HeadInsert
* 函数功能: 在链表头部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_HeadInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
}
New->next=Head->next;
Head->next->prev=New;
Head->next=New;
return true;
}
双向链表尾部插入
/*******************************************************************
*
* 函数名称: DoubleLList_TailInsert
* 函数功能: 在链表尾部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_TailInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
}
Phead->next=New;
New->prev=Phead;
return true;
}
双向链表指定部位插入
/*******************************************************************
*
* 函数名称: DoubleLList_DestInsert
* 函数功能: 在链表指定部位后面插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_DestInsert(DoubleLList_t *Head,DataType_t dest,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->data==dest && Phead->next!=NULL)
{
break;
}
}
New->next=Phead->next;
Phead->next->prev=New;
New->prev=Phead;
Phead->next=New;
return true;
}
双向链表头部删除
/*******************************************************************
*
* 函数名称: DoubleLList_HeadDel
* 函数功能: 删除双向链表头部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
*
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_HeadDel(DoubleLList_t *Head)
{
DoubleLList_t *Temp = Head->next;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
Head->next=Head->next->next;
Temp->next->prev=NULL;
Temp->next=NULL;
free(Temp);
return true;
}
双向链表尾部删除
/*******************************************************************
*
* 函数名称: DoubleLList_TailDel
* 函数功能: 删除双向链表尾部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
*
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_TailDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
while(Phead->next)
{
Phead=Phead->next;
}
Phead->prev->next=NULL;
Phead->prev=NULL;
free(Phead);
return true;
}
双向链表指定部位删除
/*******************************************************************
*
* 函数名称: DoubleLList_DestDel
* 函数功能: 删除双向链表指定部位结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_DestDel(DoubleLList_t *Head,DataType_t dest)
{
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->data==dest && Phead->next!=NULL)
{
break;
}
}
Phead->prev->next=Phead->next;
Phead->next->prev=Phead->prev;
Phead->next=NULL;
Phead->prev=NULL;
return true;
}
完整代码
/*******************************************************************
*
* file name: DoubleLinke.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 * DoubleLList_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.对头结点进行初始化,头结点是不存储数据域,指针域指向NULL
Head->prev = NULL;
Head->next = NULL;
//3.把头结点的地址返回即可
return Head;
}
//创建新的结点,并对新结点进行初始化(数据域 + 指针域)
DoubleLList_t * DoubleLList_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 = NULL;
New->next = NULL;
return New;
}
/*******************************************************************
*
* 函数名称: DoubleLList_HeadInsert
* 函数功能: 在链表头部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_HeadInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
}
New->next=Head->next;
Head->next->prev=New;
Head->next=New;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleLList_TailInsert
* 函数功能: 在链表尾部插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_TailInsert(DoubleLList_t *Head,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
}
Phead->next=New;
New->prev=Phead;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleLList_DestInsert
* 函数功能: 在链表指定部位后面插入新的结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t data 新结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/22
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_DestInsert(DoubleLList_t *Head,DataType_t dest,DataType_t data)
{
DoubleLList_t *New = DoubleLList_NewNode(data);
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
Head->next=New;
return true;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->data==dest && Phead->next!=NULL)
{
break;
}
}
New->next=Phead->next;
Phead->next->prev=New;
New->prev=Phead;
Phead->next=New;
return true;
}
/*******************************************************************
*
* 函数名称: DoubleLList_HeadDel
* 函数功能: 删除双向链表头部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
*
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_HeadDel(DoubleLList_t *Head)
{
DoubleLList_t *Temp = Head->next;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
Head->next=Head->next->next;
Temp->next->prev=NULL;
Temp->next=NULL;
free(Temp);
return true;
}
/*******************************************************************
*
* 函数名称: DoubleLList_TailDel
* 函数功能: 删除双向链表尾部结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
*
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_TailDel(DoubleLList_t *Head)
{
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
while(Phead->next)
{
Phead=Phead->next;
}
Phead->prev->next=NULL;
Phead->prev=NULL;
free(Phead);
return true;
}
/*******************************************************************
*
* 函数名称: DoubleLList_DestDel
* 函数功能: 删除双向链表指定部位结点
* 函数参数:
* @a :DoubleLList_t *Head 头结点
* @b :DataType_t dest 目标结点的数据域
* 返回结果:
* 注意事项: None
* 函数作者: m17872844806@163.com
* 创建日期: 2024/04/25
* 修改历史:
* 函数版本: V1.0
* *****************************************************************/
bool DoubleLList_DestDel(DoubleLList_t *Head,DataType_t dest)
{
DoubleLList_t *Phead = Head;
if (Head->next == NULL)
{
printf("DoubleLList_t empty!\n");
return false;
}
while(Phead->next)
{
Phead=Phead->next;
if(Phead->data==dest && Phead->next!=NULL)
{
break;
}
}
Phead->prev->next=Phead->next;
Phead->next->prev=Phead->prev;
Phead->next=NULL;
Phead->prev=NULL;
return true;
}
//遍历链表
bool DoubleLList_Print(DoubleLList_t *Head)
{
//对单向循环链表的头结点的地址进行备份
DoubleLList_t *Phead = Head;
//判断当前链表是否为空,为空则直接退出
if (Head->next == NULL)
{
printf("current linkeflist is empty!\n");
return false;
}
//从首结点开始遍历
while(Phead->next)
{
//把头结点的直接后继作为新的头结点
Phead = Phead->next;
//输出头结点的直接后继的数据域
printf("data = %d\n",Phead->data);
}
return true;
}
int main(int argc, char const *argv[])
{
DoubleLList_t *phe=DoubleLList_Create();
DoubleLList_HeadInsert(phe,20);
DoubleLList_HeadInsert(phe,10);
DoubleLList_TailInsert(phe,40);
DoubleLList_TailInsert(phe,50);
DoubleLList_DestInsert(phe,20,30);
DoubleLList_HeadDel(phe);
DoubleLList_TailDel(phe);
DoubleLList_DestDel(phe,30);
DoubleLList_Print(phe);
return 0;
}
该代码成功运行后,可以在终端肯定data的值为20,40
如果代码双向链表的代码有什么问题,请将问题发至网易邮箱 m17872844806@163.com,作者将及时改正,欢迎各位老爷提出意见。
麻烦三连加关注!!!!
比心!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理