双向循环链表
双向循环链表
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef int DataType_t;
// 构造双向循环链表的结点
typedef struct DoublyCirLinkedList
{
DataType_t data; // 节点的数据域
struct DoublyCirLinkedList *prev; // 节点的前向指针域
struct DoublyCirLinkedList *next; // 节点的后向指针域
} DoublyCirLiList_t;
// 创建一个空双向循环链表,空链表应该有一个头节点,对链表进行初始化
DoublyCirLiList_t *DoublyCirLiList_Creat(void)
{
// 1. 创建一个头结点,为头节点申请内存
DoublyCirLiList_t *Head = (DoublyCirLiList_t *)calloc(1, sizeof(DoublyCirLiList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is failed");
return NULL;
}
// 2. 对头节点进行初始化,头节点不存储有效内容,指针域指向自身形成循环
Head->prev = Head;
Head->next = Head;
// 3. 把头结点的地址返回即可
return Head;
}
// 创建链表的新的节点并对链表进行初始化
DoublyCirLiList_t *DoublyCirLiList_NewNode(DataType_t data)
{
// 1. 创建一个新结点,为新节点申请内存
DoublyCirLiList_t *New = (DoublyCirLiList_t *)calloc(1, sizeof(DoublyCirLiList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is failed");
return NULL;
}
// 2. 对新节点进行初始化
New->data = data;
New->prev = NULL;
New->next = NULL;
return New;
}
// 将新的节点插入到链表首节点//头插
bool DoublyCirLiList_HeadInsert(DoublyCirLiList_t *Head, DataType_t data)
{
// 1. 创建新节点并对新节点进行初始化
DoublyCirLiList_t *New = DoublyCirLiList_NewNode(data);
if (NULL == New)
{
perror("can not insert new node\n");
return false;
}
// 2. 将新节点插入到链表头部
New->next = Head->next;
New->prev = Head;
Head->next->prev = New;
Head->next = New;
return true;
}
// 将新的节点插入到链表尾节点//尾插
bool DoublyCirLiList_TailInsert(DoublyCirLiList_t *Head, DataType_t data)
{
// 1. 创建新节点并对新节点进行初始化
DoublyCirLiList_t *New = DoublyCirLiList_NewNode(data);
if (NULL == New)
{
perror("can not insert new node\n");
return false;
}
// 2. 将新节点插入到链表尾部
New->prev = Head->prev;
New->next = Head;
Head->prev->next = New;
Head->prev = New;
return true;
}
// 将新的节点插入到链表指定节点之后//指定插
bool DoublyCirLiList_DestInsert(DoublyCirLiList_t *Head, DataType_t dest, DataType_t data)
{
// 1. 创建新节点并对新节点进行初始化
DoublyCirLiList_t *New = DoublyCirLiList_NewNode(data);
if (NULL == New)
{
perror("can not insert new node\n");
return false;
}
// 2. 找到指定节点
DoublyCirLiList_t *Phead = Head->next;
while (Phead != Head && Phead->data != dest)
{
Phead = Phead->next;
}
if (Phead == Head)
{
printf("data is not found\n");
return false;
}
// 3. 将新节点插入到指定节点之后
New->next = Phead->next;
New->prev = Phead;
Phead->next->prev = New;
Phead->next = New;
return true;
}
// 遍历
void DoublyCirLiList_Print(DoublyCirLiList_t *Head)
{
// 对链表的头节点的下一个节点的地址进行备份
DoublyCirLiList_t *Phead = Head->next;
while (Phead != Head)
{
// 输出当前节点的数据域
printf("data = %d\n", Phead->data);
// 输出当前节点的前一个节点和后一个节点的地址
printf("prev = %p, next = %p\n", (void *)Phead->prev, (void *)Phead->next);
// 移动到下一个节点
Phead = Phead->next;
}
}
// 删除首节点
bool DoublyCirLiList_HeadDel(DoublyCirLiList_t *Head)
{
// 检查链表是否为空
if (Head == NULL || Head->next == Head)
{
// 若为空,输出错误信息并返回false
perror("The LiList is empty");
return false;
}
// 标记要删除的首节点
DoublyCirLiList_t *DelNode = Head->next;
// 让头节点的next指针指向要删除节点的下一个节点
Head->next = DelNode->next;
// 让要删除节点的下一个节点的prev指针指向头节点
DelNode->next->prev = Head;
// 释放要删除节点的内存
free(DelNode);
// 删除成功,返回true
return true;
}
// 删除尾节点
bool DoublyCirLiList_TailDel(DoublyCirLiList_t *Head)
{
// 检查链表是否为空
if (Head == NULL || Head->next == Head)
{
// 若为空,输出错误信息并返回false
perror("The LiList is empty");
return false;
}
// 标记要删除的尾节点
DoublyCirLiList_t *DelNode = Head->prev;
// 让头节点的prev指针指向要删除节点的前一个节点
Head->prev = DelNode->prev;
// 让要删除节点的前一个节点的next指针指向头节点
DelNode->prev->next = Head;
// 释放要删除节点的内存
free(DelNode);
// 删除成功,返回true
return true;
}
// 删除指定节点
bool DoublyCirLiList_DestDel(DoublyCirLiList_t *Head, DataType_t dest)
{
// 检查链表是否为空
if (Head == NULL || Head->next == Head)
{
// 若为空,输出错误信息并返回false
perror("The LiList is empty");
return false;
}
// 从头节点的下一个节点开始遍历链表
DoublyCirLiList_t *Phead = Head->next;
// 寻找数据域等于dest的节点
while (Phead != Head && Phead->data != dest)
{
// 移动到下一个节点
Phead = Phead->next;
}
// 若未找到指定节点
if (Phead == Head)
{
// 输出提示信息并返回false
printf("data is not found\n");
return false;
}
// 让指定节点的前一个节点的next指针指向指定节点的下一个节点
Phead->prev->next = Phead->next;
// 让指定节点的下一个节点的prev指针指向指定节点的前一个节点
Phead->next->prev = Phead->prev;
// 释放指定节点的内存
free(Phead);
// 删除成功,返回true
return true;
}
// 主函数,程序的入口
int main(int argc, char const *argv[])
{
// 创建一个空的双向循环链表
DoublyCirLiList_t *Head = DoublyCirLiList_Creat();
// 向链表尾部插入数据1
DoublyCirLiList_TailInsert(Head, 1);
// 向链表尾部插入数据2
DoublyCirLiList_TailInsert(Head, 2);
// 向链表尾部插入数据3
DoublyCirLiList_TailInsert(Head, 3);
// 向链表尾部插入数据4
DoublyCirLiList_TailInsert(Head, 4);
// 打印链表中的数据
DoublyCirLiList_Print(Head);
// 换行,用于分隔不同操作的输出结果
printf("\n");
// 向链表头部插入数据6
DoublyCirLiList_HeadInsert(Head, 6);
// 可以在此处调用其他操作函数进行测试
// 再次打印链表中的数据
DoublyCirLiList_Print(Head);
// 换行,用于分隔不同操作的输出结果
printf("\n");
// 删除链表的首节点
DoublyCirLiList_HeadDel(Head);
// 打印链表中的数据
DoublyCirLiList_Print(Head);
// 换行,用于分隔不同操作的输出结果
printf("\n");
// 删除链表的尾节点
DoublyCirLiList_TailDel(Head);
// 打印链表中的数据
DoublyCirLiList_Print(Head);
// 输出头节点的地址
printf("Head = %p\n", (void *)Head);
// 程序正常结束,返回0
return 0;
}
运行结果


浙公网安备 33010602011771号