双向循环链表
/********************************************************************************
*
- file name: DoublecirCulateLinkedList.c
- author : yxw18679428019@163.com
- date : 2024/04/25
- function : 双向循环链表
- note : None
- CopyRight (c) 2023-2024 yxw18679428019@163.com All Right Reseverd
- ****************************************************************************/
include <stdio.h>
include <stdlib.h>
include <stdbool.h>
// 指的是双向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
// 构造双向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct DoublecirCulateLinkedList
{
DataType_t data; // 结点的数据域
struct DoublecirCulateLinkedList *prev; // 直接前驱的指针域
struct DoublecirCulateLinkedList *next; // 直接后继的指针域
} DoubleCirLList_t;
/*******************************************************************************
- name : DoubleCirLList_Create
- function : 创建一个空双向循环链表,空链表应该有一个头结点,对链表进行初始化
- argument : None
- retval : 返回头结点的地址
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
DoubleCirLList_t *DoubleCirLList_Create(void)
{
// 1.创建一个头结点并对头结点申请内存
DoubleCirLList_t *Head = (DoubleCirLList_t *)calloc(1, sizeof(DoubleCirLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}
// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向自身即可,体现“循环”
Head->prev = Head;
Head->next = Head;
// 3.把头结点的地址返回即可
return Head;
}
/*******************************************************************************
- name : DoubleCirLList_NewNode
- function : 创建新的结点,并对新结点进行初始化(数据域 + 指针域)
- argument : None
- retval : 返回新结点的地址
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
DoubleCirLList_t *DoubleCirLList_NewNode(DataType_t data)
{
// 1.创建一个新结点并对新结点申请内存
DoubleCirLList_t *New = (DoubleCirLList_t *)calloc(1, sizeof(DoubleCirLList_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;
}
/*******************************************************************************
- name : DoubleCirLList_HeadInsert
- function : 头部插入结点
- argument :
-
@Head :头结点的地址
-
@data :插入结点的数据
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_HeadInsert(DoubleCirLList_t *Head, DataType_t data)
{
DoubleCirLList_t *Phead = Head->next; // 备份新首结点的地址
// 创建新的结点并对结点进行初始化
DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("can not insert New Node");
return false;
}
// 判断链表是否为空
if (Head->next == Head)
{
Head->next = New;
return true;
}
// 链表不为空
Phead->prev->next = New; // 尾结点的next指针指向新结点
New->prev = Phead->prev; // 新结点的prev指针指向尾结点
New->next = Phead; // 新结点的next指针指向首结点
Phead->prev = New; // 首结点的prev指针指向新结点
Head->next = New; // 头结点的next指针指向新结点
return true;
}
/*******************************************************************************
- name : DoubleCirLList_TailInsert
- function : 尾部插入结点
- argument :
-
@Head :头结点的地址
-
@data :插入结点的数据
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_TailInsert(DoubleCirLList_t *Head, DataType_t data)
{
// 创建新的结点并对结点进行初始化
DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("can not insert New Node");
return false;
}
// 判断链表是否为空,则直接插入到首结点后
if (Head->next == Head)
{
Head->next = New;
return true;
}
// 链表不为空
New->prev = Head->next->prev; // 新结点的perv指针指向尾结点
Head->next->prev->next = New; // 把尾结点的next指针指向新结点
New->next = Head->next; // 新结点的next指针指向首结点
Head->next->prev = New; // 首结点的next指针指向新结点
}
/*******************************************************************************
- name : DoubleCirLList_DestInsert
- function : 插入到指定结点的尾部
- argument :
-
@Head :头结点的地址
-
@data :插入结点的数据
-
@DestVal :指定插入位置的结点数据
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_DestInsert(DoubleCirLList_t *Head, DataType_t DestVal, DataType_t data)
{
DoubleCirLList_t *Phead = Head->next; // 备份首结点
// 创建新的结点并对结点进行初始化
DoubleCirLList_t *New = DoubleCirLList_NewNode(data);
if (NULL == New)
{
printf("can not insert New Node");
return false;
}
// 判断链表是否为空,则直接插入到首结点后
if (Head->next == Head)
{
Head->next = New;
return true;
}
while (Phead->next != Head->next)
{
if (DestVal == Phead->data)
{
break;
}
Phead = Phead->next;
}
// 遍历到尾结点还未找到这插入失败
if (Phead->next == Head->next && Phead->data != DestVal)
{
return false;
}
if (Phead->data == DestVal) // 指点插入
{
New->prev = Phead; // 新结点的prev指针指向目标结点
New->next = Phead->next; // 新结点的next指针指向目标结点的直接后继
Phead->next->prev = New; // 目标结点的直接后继的prev指针指向新结点
Phead->next = New; // 把目标结点的next指针指向新结点
}
else // 尾插
{
New->prev = Phead; // 把新结点的prev指针指向目标结点
New->next = Head->next; // 把新结点的next指针指向首结点
Head->next->prev = New; // 把首结点的prev指针指向新结点
Phead->next = New; // 把指定结点的next指针指向新结点
}
}
/*******************************************************************************
- name : DoubleCirLList_HeadDel
- function : 头部删除结点
- argument :
-
@Head :头结点的地址
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_HeadDel(DoubleCirLList_t *Head)
{
DoubleCirLList_t *Phead = Head->next; // 备份首结点的地址
// 判断链表是否为空
if (Head == Head->next)
{
printf(" Linked list is empty");
return false;
}
// 链表非空
Phead->prev->next = Phead->next; // 尾结点的next指针指向待删除结点的直接后继
Phead->next->prev = Phead->prev; // 待删除结点的直接后继的perv指针指向尾结点
Head->next = Phead->next; // 头结点的next指针指向待删除结点的直接后继
Phead->next = NULL; // 首结点的next指针指向NULL
Phead->prev = NULL; // 首结点的prev指针指向NULL
free(Phead); // 释放首结点内存
return true;
}
/*******************************************************************************
- name : DoubleCirLList_TailDel
- function : 尾部删除结点
- argument :
-
@Head :头结点的地址
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_TailDel(DoubleCirLList_t *Head)
{
DoubleCirLList_t *tail = Head->next->prev; // 记录尾结点的地址
// 判断链表是否为空
if (Head == Head->next)
{
printf("Linked list is empty");
return false;
}
// 链表为非空
tail->prev->next = Head->next; // 尾结点的直接前驱的next指针指向首结点
Head->next->prev = tail->prev; // 首结点的next指针指向尾结点的直接前驱
tail->prev = NULL; // 尾结点的prev指针指向NULL
tail->next = NULL; // 尾结点的next指针指向NULL
free(tail); // 释放尾结点内存
}
/*******************************************************************************
- name : DoubleCirLList_DestDel
- function : 指定删除结点
- argument :
-
@Head :头结点的地址
-
@DeatVal :指定结点的数据
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_DestDel(DoubleCirLList_t *Head, DataType_t DestVal)
{
DoubleCirLList_t *Phead = Head->next; // 记录首结点的地址
// 判断链表是否为空
if (Head == Head->next)
{
printf("Linked list is empty");
return false;
}
// 判断是否只有一个首结点
if (Phead->next == Head->next)
{
Phead->next = NULL; // 首结点的next指针指向NULL
Phead->prev = NULL; // 首结点的prev指针指向NULL
Head->next = Head; // 头结点指向本身
}
while (Phead->next != Head->next)
{
if (DestVal == Phead->data)
{
break;
}
Phead = Phead->next;
}
if (Phead == Head->next) // 头删
{
Phead->prev->next = Phead->next; // 尾结点的next指针指向待删除结点的直接后继
Phead->next->prev = Head->prev; // 带删除结点的直接后继的prev指针指向尾结点
Head->next = Phead->next; // 头结点的next指针指向待删除结点的直接后继
Phead->next = NULL; // 待删除结点的next指针指向NULL
Phead->prev = NULL; // 待删除结点的prev指针指向NULL
free(Phead); // 释放首结点的内存
}
else if (DestVal == Phead->data) // 尾部删除
{
Phead->prev->next = Head->next; // 待删除点的直接前驱的next指针指向首结点
Head->next->prev = Phead->prev; // 首结点的prev指针指向待删除结点的直接前驱
Phead->prev = NULL; // 待删除结点的prev指针指向NULL
Phead->next = NULL; // 待删除结点的next指针指向NULL
free(Phead); // 释放删除结点的内存
}
else
{
Phead->prev->next = Phead->next; // 待删除结点的直接前驱的next指针指向待删除结点的直接后继
Phead->next->prev = Phead->prev; // 待删除结点的直接后继的prev指针指向待删除结点的直接前驱
Phead->prev = NULL; // 待删除结点的prev指针指向NULL
Phead->next = NULL; // 待删除结点的next指针指向NULL
free(Phead); // 释放删除结点内存
}
}
/*******************************************************************************
- name : DoubleCirLList_Print
- function : 遍历双向链表的中的每个结点,并输出每个结点的数据
- argument :
-
@Head :头结点的地址
- retval : true and false
- author : yxw18679428019@163.com
- date : 2024/04/25
- note : None
- ***************************************************************************/
bool DoubleCirLList_Print(DoubleCirLList_t *Head)
{
// 对单向循环链表的头结点的地址进行备份
DoubleCirLList_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)
{
break;
}
}
return true;
}
int main(int argc, char const *argv[])
{
DoubleCirLList_t *Head = DoubleCirLList_Create();
// 头部插入
DoubleCirLList_HeadInsert(Head, 3);
DoubleCirLList_HeadInsert(Head, 5);
DoubleCirLList_Print(Head);
printf("\n");
// 尾部插入
DoubleCirLList_TailInsert(Head, 1);
DoubleCirLList_TailInsert(Head, 2);
DoubleCirLList_Print(Head);
printf("\n");
// 指定插入
DoubleCirLList_DestInsert(Head, 2, 4);
DoubleCirLList_Print(Head);
printf("\n");
// 头删
DoubleCirLList_HeadDel(Head);
DoubleCirLList_HeadDel(Head);
DoubleCirLList_Print(Head);
printf("\n");
// 尾删
DoubleCirLList_TailDel(Head);
DoubleCirLList_TailDel(Head);
DoubleCirLList_Print(Head);
printf("\n");
// 指定删除
DoubleCirLList_DestDel(Head, 1);
DoubleCirLList_Print(Head);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现