数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)
版本:
2024年4月25日 V1.0 发布于博客园
/**
* @file name : CircularLinkedList.c
* @brief : 实现单向循环链表的相关功能
* @author :RISE_AND_GRIND@163.com
* @date :2024/04/25
* @version :1.1
* @note :
* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd
*/
目录
目录
单向循环链表公式
/**
* 声明单循环链表的结点
*
* 单向循环链表总结成公式
* struct xxx
* {
* //数据域(需要存放什么类型的数据,你就定义对应的变量即可)
* //指针域(直接后继的指针域)
* };
* 单向循环链表的基本操作:
* 初始化单向循环链表 √
* 插入数据 √
* 删除数据 √
* 修改数据
* 查询打印数据√
*/
初始化单向循环链表
构建单向循环链表结点
CircLList_t[ data |*next ]
// 指的是单向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
// 构造单向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct CircularLinkedList
{
DataType_t data; // 结点的数据域
struct CircularLinkedList *next; // 直接后继的指针域
} CircLList_t;
创建一个空链表(仅头结点)
/**
* @name CircLList_Create
* @brief 创建一个空单向循环链表,仅含头结点,并对链表进行初始化
* @param
* @return
* @retval Head 头结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_Create(void)
{
// 1.创建一个头结点并对头结点申请内存
CircLList_t *Head = (CircLList_t *)calloc(1, sizeof(CircLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}
// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向自己, 体现循环的思想 [date|*next]
Head->next = Head;
// 3.把头结点的地址返回即可 Head-->[date|*next]
return Head;
}
创建一个新结点
/**
* @name CircLList_NewNode
* @brief 创建一个新的结点,并对新结点进行初始化(数据域 + 指针域)
* @param data 要创建结点的元素
* @return 程序执行成功与否
* @retval NULL 申请堆内存失败
* @retval New 新结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_NewNode(DataType_t data)
{
// 1.创建一个新结点并对新结点申请内存
CircLList_t *New = (CircLList_t *)calloc(1, sizeof(CircLList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is Failed");
return NULL;
}
// 2.对新结点的数据域和指针域进行初始化
New->data = data;
New->next = NULL;
return New;
}
插入数据
头插
/**
* @name CircLList_HeadInsert
* @brief 在单向循环链表的头结点后插入
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadInsert(CircLList_t *Head, DataType_t data)
{
// 备份头指针, 创建操作指针
CircLList_t *Current = Head;
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则直接插入到头结点之后, 新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环, 仅有一个首结点的单循环链表
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向首结点
while (Current->next) // 不断向下检查结点指针域
{
Current = Current->next; // 进入下一个结点
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Current到达未尾结点
Current->next = New; // 尾结点指针域指向新的首结点
New->next = Head->next; // 新结点链接旧首结点
Head->next = New; // 头结点的next指针域指向新结点的地址
return true;
}
中插
/**
* @name CircLList_DestInsert
* @brief 单向循环链表中的指定元素后面插入新结点
* @param Head 头指针
* @param dest 要查找的结点
* @param data 要插入的数据
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestInsert(CircLList_t *Head, DataType_t dest, DataType_t data)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环, 单有效结点
return true;
}
// 3.若单向循环链表非空,需要让尾结点的next指针指向新结点,新结点指向首结点
// 目标结点是首结点, 不再继续查找. 目标结点非首结点, 继续向下查找
while (Current->data != dest)
{
Current = Current->next; // 进入下一个结点
if ((Current->next == Head->next) && (Current->data != dest)) // 达到末尾 且 末尾不是目标
{
printf("The target doesn't exist! \n");
return false;
}
} // 找到目标结点, Current此时指向目标
// 目标结点是首结点
if (Current == Head->next)
{
New->next = Current->next; // 新结点链接目标结点直接后继
Current->next = New;
}
else if (Current->next == Head->next) // 目标结点是尾结点
{
New->next = Head->next; // 作为新尾结点
Current->next = New;
}
else // 目标结点是中间结点
{
New->next = Current->next; // 新结点链接目标结点直接后继
Current->next = New; // 目标结点的直接后继更新为新结点
}
return true;
}
尾插
/**
* @name CircLList_TailInsert
* @brief 将新元素插入到尾结点后面
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_TailInsert(CircLList_t *Head, DataType_t data)
{
CircLList_t *Phead = Head; // 备份头结点地址,防止头结点丢失
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向新结点,新结点指向首结点
while (Phead->next) // 不断向下检查结点指针域
{
Phead = Phead->next; // 进入下一个结点
if (Phead->next == Head->next) // 当到达尾结点
{
break;
}
}
Phead->next = New; // 尾结点指针域 链接 新结点
New->next = Head->next; // 新结点指针域 指向 首结点
return true;
}
删除数据
头删
/**
* @name CircLList_HeadDel
* @brief 删除头结点后面的一个结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败
* @retval true 删除成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadDel(CircLList_t *Head)
{
// 1.创建操作指针
// 备份头结点地址,防止头结点丢失
CircLList_t *Phead = Head;
// 备份首结点, 用于操作
CircLList_t *Temp = Head->next;
// 2.判断单向循环链表是否为空链表,如果为空, 则退出
if (Head == Head->next)
{
printf("CircLList is Empty! \n");
return false;
}
// 3.判断链表中是否只有首结点
if (Head->next == Head->next->next)
{
Temp->next = NULL; // 首结点的指针域指向NULL, 且防止野指针和内存泄漏
Head->next = Head; // 头结点next指针指向头结点, 体现"循环"
free(Temp); // 释放结点内存, 防止内存泄漏
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向新的首结点(原首结点的直接后继)
while (Phead->next) // 不断向下检查结点指针域
{
Phead = Phead->next; // 进入下一个结点
if (Phead->next == Head->next) // 当到达尾结点
{
break;
}
}
Phead->next = Head->next->next; // 让尾结点的next指针指向新的首结点(原首结点的直接后继)
Head->next = Phead->next; // 头结点的指针域 修改链接为 新的首结点
Temp->next = NULL; // 让旧的首结点的指针域指向NULL, 从链表中断开, 且防止野指针和内存泄漏
free(Temp); // 释放旧首结点的内存, 防止内存泄漏
return true;
}
中删
/**
* @name CircLList_DestDel
* @brief 中删, 删除某个元素结点
* @param Head 头指针
* @param dest 要删除的目标元素
* @return 程序执行成功与否
* @retval false 删除失败, 未找到目标元素结点
* @retval true 删除成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestDel(CircLList_t *Head, DataType_t dest)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
CircLList_t *Prev = Head; // 操作指针 存放当前操作指针的前一个结点地址
// 1.判断单向循环链表是否为空,如果为空,则报错
if (Head == Head->next)
{
printf("Error, CircularLinkList is empty! \n");
return false;
}
// 2.若单向循环链表非空
// 目标结点是首结点, 不再继续查找. 目标结点非首结点, 继续向下查找
while (Current->data != dest)
{
Prev = Current; // 备份Current的前一个位置
Current = Current->next; // 进入下一个结点
if ((Current->next == Head->next) && (Current->data != dest)) // 达到末尾 且 末尾不是目标
{
printf("The target doesn't exist! \n");
return false;
}
} // 找到目标结点, Current此时指向目标 Prev为Current 的前一个位置
// 目标结点是首结点
if (Current == Head->next)
{
// 若链表只有首结点
if (Current->next == Head->next)
{
Head->next = Head; // 空链表状态
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
while (Prev->next) // 不断向下检查结点指针域
{
Prev = Prev->next; // 进入下一个结点
if (Prev->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Prev到达未尾结点
Prev->next = Current->next; // 更新尾结点指针域为新首结点地址
Head->next = Current->next; // 更新首结点链接新首结点
}
else if (Current->next == Head->next) // 目标结点是尾结点
{
Prev->next = Head->next; // 新尾结点链接首结点, 行成循环
}
else // 目标结点是中间结点
{
Prev->next = Current->next;
}
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
尾删
/**
* @name CircLList_TailDel
* @brief 删除尾结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败, 链表为空
* @retval true 删除成功
* @date 2024/04/25
* @version 1.0
* @note
*/
bool CircLList_TailDel(CircLList_t *Head)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
CircLList_t *Prev = Head; // 操作指针 存放当前操作指针的前一个结点地址
// 1.判断单向循环链表是否为空,如果为空,则报错
if (Head == Head->next)
{
printf("Error, CircularLinkList is empty! \n");
return false;
}
// 2.若单向循环链表非空
// 若链表只有首结点
if (Current->next == Head->next)
{
Head->next = Head; // 空链表状态
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
// 若还有别的结点
while (Current->next) // 不断向下检查结点指针域
{
Prev = Current;
Current = Current->next; // 进入下一个结点
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Current到达未尾结点 Prev为Current 的前一个位置
Prev->next = Head->next; // 新尾结点链接首结点, 行成循环
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
查询打印数据
遍历打印
/**
* @name CircLList_Print
* @brief 从头到尾遍历链表
* @param Head 头指针
* @return 无
* @date 2024/04/23
* @version 1.0
* @note
*/
void CircLList_Print(CircLList_t *Head)
{
// 判断是否为空链表
if (Head->next == Head)
{
printf("The list is empty.\n");
return;
}
CircLList_t *Current = Head->next; // 指向首结点
printf("Circular Linked List: ");
while (Current->next) // 不断向下检查结点指针域
{
printf(" -> %d", Current->data); // 打印结点数据
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
Current = Current->next; // 进入下一个结点
}
printf("\n"); // 刷新行缓冲, 输出缓冲区
}
测试
#include "CircularLinkedList.h"
int main(int argc, char const *argv[])
{
// 创建单向循环链表, 空链表
CircLList_t *Manager = CircLList_Create();
// 头插法 向链表中插入新结点
printf("*********************************CircLList_HeadInsert********************************\n");
CircLList_HeadInsert(Manager, 7);
CircLList_HeadInsert(Manager, 4);
CircLList_HeadInsert(Manager, 1);
CircLList_HeadInsert(Manager, 8);
CircLList_HeadInsert(Manager, 5);
CircLList_HeadInsert(Manager, 2);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 5 -> 8 -> 1 -> 4 -> 7*/
// 中插法 向链表中插入新结点
printf("*********************************CircLList_DestInsert********************************\n");
CircLList_DestInsert(Manager, 7, 9);
CircLList_DestInsert(Manager, 4, 6);
CircLList_DestInsert(Manager, 2, 3);
CircLList_DestInsert(Manager, 5, 10);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9*/
// 尾插法 向链表中插入新结点
printf("*********************************CircLList_TailInsert********************************\n");
CircLList_TailInsert(Manager, 13);
CircLList_TailInsert(Manager, 12);
CircLList_TailInsert(Manager, 11);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11*/
// 头删法 删除首结点
printf("*********************************CircLList_HeadDel********************************\n");
CircLList_HeadDel(Manager);
CircLList_HeadDel(Manager);
CircLList_HeadDel(Manager);
CircLList_Print(Manager);
/*Circular Linked List: -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11*/
// 中删法 删除指定结点
printf("*********************************CircLList_DestDel********************************\n");
CircLList_DestDel(Manager, 10);
CircLList_DestDel(Manager, 1);
CircLList_DestDel(Manager, 6);
CircLList_DestDel(Manager, 11);
CircLList_Print(Manager);
/*Circular Linked List: -> 8 -> 4 -> 7 -> 9 -> 13 -> 12*/
// 尾删法 删除尾结点
printf("*********************************CircLList_HeadDel********************************\n");
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_Print(Manager);
/*Circular Linked List: -> 8 -> 4*/
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
/*Error, CircularLinkList is empty! */
CircLList_HeadInsert(Manager, 66);
CircLList_Print(Manager);
/*Circular Linked List: -> 66*/
// 等待用户响应
printf("***Press any key to exit the test***\n");
getchar();
return 0;
}
测试结果:
*********************************CircLList_HeadInsert********************************
Circular Linked List: -> 2 -> 5 -> 8 -> 1 -> 4 -> 7
*********************************CircLList_DestInsert********************************
Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9
*********************************CircLList_TailInsert********************************
Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11
*********************************CircLList_HeadDel********************************
Circular Linked List: -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11
*********************************CircLList_DestDel********************************
Circular Linked List: -> 8 -> 4 -> 7 -> 9 -> 13 -> 12
*********************************CircLList_HeadDel********************************
Circular Linked List: -> 8 -> 4
Error, CircularLinkList is empty!
Circular Linked List: -> 66
***Press any key to exit the test***
完整代码
CircularLinkedList.h
#ifndef __CIRCULARLINKEDLIST_H // ifndef是(如果 没有 定义 那么) (__该头文件的名称)
#define __CIRCULARLINKEDLIST_H // #define是 进行定义
/**
* @file name : CircularLinkedList.c
* @brief : 实现单向循环链表的相关功能
* @author :RISE_AND_GRIND@163.com
* @date :2024/04/25
* @version :1.1
* @note :
* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
/**
* 声明单循环链表的结点
*
* 单向循环链表总结成公式
* struct xxx
* {
* //数据域(需要存放什么类型的数据,你就定义对应的变量即可)
* //指针域(直接后继的指针域)
* };
* 单向循环链表的基本操作:
* 初始化单向循环链表 √
* 插入数据 √
* 删除数据 √
* 修改数据
* 查询打印数据√
*/
// 指的是单向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
// 构造单向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct CircularLinkedList
{
DataType_t data; // 结点的数据域
struct CircularLinkedList *next; // 直接后继的指针域
} CircLList_t;
/**
* @name CircLList_Create
* @brief 创建一个空单向循环链表,仅含头结点,并对链表进行初始化
* @param
* @return
* @retval Head 头结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_Create(void);
/**
* @name CircLList_NewNode
* @brief 创建一个新的结点,并对新结点进行初始化(数据域 + 指针域)
* @param data 要创建结点的元素
* @return 程序执行成功与否
* @retval NULL 申请堆内存失败
* @retval New 新结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_NewNode(DataType_t data);
/**
* @name CircLList_HeadInsert
* @brief 在单向循环链表的头结点后插入
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadInsert(CircLList_t *Head, DataType_t data);
/**
* @name CircLList_DestInsert
* @brief 单向循环中的指定元素后面插入新结点
* @param Head 头指针
* @param dest 要查找的结点
* @param data 要插入的数据
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestInsert(CircLList_t *Head, DataType_t dest, DataType_t data);
/**
* @name CircLList_TailInsert
* @brief 将新元素插入到尾结点后面
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_TailInsert(CircLList_t *Head, DataType_t data);
/**
* @name CircLList_HeadDel
* @brief 删除头结点后面的一个结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败
* @retval true 删除成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadDel(CircLList_t *Head);
/**
* @name CircLList_DestDel
* @brief 中删, 删除某个元素结点
* @param Head 头指针
* @param dest 要删除的目标元素
* @return 程序执行成功与否
* @retval false 删除失败, 未找到目标元素结点
* @retval true 删除成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestDel(CircLList_t *Head, DataType_t dest);
/**
* @name CircLList_TailDel
* @brief 删除尾结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败, 链表为空
* @retval true 删除成功
* @date 2024/04/25
* @version 1.0
* @note
*/
bool CircLList_TailDel(CircLList_t *Head);
/**
* @name CircLList_Print
* @brief 从头到尾遍历链表
* @param Head 头指针
* @return 无
* @date 2024/04/23
* @version 1.0
* @note
*/
void CircLList_Print(CircLList_t *Head);
#endif
// 结束定义
CircularLinkedList.c
/**
* @file name : CircularLinkedList.c
* @brief : 实现单向循环链表的相关功能
* @author :RISE_AND_GRIND@163.com
* @date :2024/04/25
* @version :1.1
* @note :
* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd
*/
#include "CircularLinkedList.h"
/**
* @name CircLList_Create
* @brief 创建一个空单向循环链表,仅含头结点,并对链表进行初始化
* @param
* @return
* @retval Head 头结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_Create(void)
{
// 1.创建一个头结点并对头结点申请内存
CircLList_t *Head = (CircLList_t *)calloc(1, sizeof(CircLList_t));
if (NULL == Head)
{
perror("Calloc memory for Head is Failed");
exit(-1);
}
// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向自己, 体现循环的思想 [date|*next]
Head->next = Head;
// 3.把头结点的地址返回即可 Head-->[date|*next]
return Head;
}
/**
* @name CircLList_NewNode
* @brief 创建一个新的结点,并对新结点进行初始化(数据域 + 指针域)
* @param data 要创建结点的元素
* @return 程序执行成功与否
* @retval NULL 申请堆内存失败
* @retval New 新结点地址
* @date 2024/04/24
* @version 1.0
* @note
*/
CircLList_t *CircLList_NewNode(DataType_t data)
{
// 1.创建一个新结点并对新结点申请内存
CircLList_t *New = (CircLList_t *)calloc(1, sizeof(CircLList_t));
if (NULL == New)
{
perror("Calloc memory for NewNode is Failed");
return NULL;
}
// 2.对新结点的数据域和指针域进行初始化
New->data = data;
New->next = NULL;
return New;
}
/**
* @name CircLList_HeadInsert
* @brief 在单向循环链表的头结点后插入
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadInsert(CircLList_t *Head, DataType_t data)
{
// 备份头指针, 创建操作指针
CircLList_t *Current = Head;
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则直接插入到头结点之后, 新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环, 仅有一个首结点的单循环链表
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向首结点
while (Current->next) // 不断向下检查结点指针域
{
Current = Current->next; // 进入下一个结点
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Current到达未尾结点
Current->next = New; // 尾结点指针域指向新的首结点
New->next = Head->next; // 新结点链接旧首结点
Head->next = New; // 头结点的next指针域指向新结点的地址
return true;
}
/**
* @name CircLList_DestInsert
* @brief 单向循环链表中的指定元素后面插入新结点
* @param Head 头指针
* @param dest 要查找的结点
* @param data 要插入的数据
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestInsert(CircLList_t *Head, DataType_t dest, DataType_t data)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环, 单有效结点
return true;
}
// 3.若单向循环链表非空,需要让尾结点的next指针指向新结点,新结点指向首结点
// 目标结点是首结点, 不再继续查找. 目标结点非首结点, 继续向下查找
while (Current->data != dest)
{
Current = Current->next; // 进入下一个结点
if ((Current->next == Head->next) && (Current->data != dest)) // 达到末尾 且 末尾不是目标
{
printf("The target doesn't exist! \n");
return false;
}
} // 找到目标结点, Current此时指向目标
// 目标结点是首结点
if (Current == Head->next)
{
New->next = Current->next; // 新结点链接目标结点直接后继
Current->next = New;
}
else if (Current->next == Head->next) // 目标结点是尾结点
{
New->next = Head->next; // 作为新尾结点
Current->next = New;
}
else // 目标结点是中间结点
{
New->next = Current->next; // 新结点链接目标结点直接后继
Current->next = New; // 目标结点的直接后继更新为新结点
}
return true;
}
/**
* @name CircLList_TailInsert
* @brief 将新元素插入到尾结点后面
* @param Head 头指针
* @param data 新元素
* @return 程序执行成功与否
* @retval false 插入失败
* @retval true 插入成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_TailInsert(CircLList_t *Head, DataType_t data)
{
CircLList_t *Phead = Head; // 备份头结点地址,防止头结点丢失
// 1.创建新结点并对新结点进行初始化
CircLList_t *New = CircLList_NewNode(data);
if (NULL == New)
{
printf("can not insert new node , Failed to create a node\n");
return false;
}
// 2.判断单向循环链表是否为空,如果为空,则新结点作为首结点, 体现循环
if (Head == Head->next)
{
Head->next = New; // 让头结点的next指针指向新结点
New->next = New; // 新节点指向自己, 体现循环
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向新结点,新结点指向首结点
while (Phead->next) // 不断向下检查结点指针域
{
Phead = Phead->next; // 进入下一个结点
if (Phead->next == Head->next) // 当到达尾结点
{
break;
}
}
Phead->next = New; // 尾结点指针域 链接 新结点
New->next = Head->next; // 新结点指针域 指向 首结点
return true;
}
/**
* @name CircLList_HeadDel
* @brief 删除头结点后面的一个结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败
* @retval true 删除成功
* @date 2024/04/24
* @version 1.0
* @note
*/
bool CircLList_HeadDel(CircLList_t *Head)
{
// 1.创建操作指针
// 备份头结点地址,防止头结点丢失
CircLList_t *Phead = Head;
// 备份首结点, 用于操作
CircLList_t *Temp = Head->next;
// 2.判断单向循环链表是否为空链表,如果为空, 则退出
if (Head == Head->next)
{
printf("CircLList is Empty! \n");
return false;
}
// 3.判断链表中是否只有首结点
if (Head->next == Head->next->next)
{
Temp->next = NULL; // 首结点的指针域指向NULL, 且防止野指针和内存泄漏
Head->next = Head; // 头结点next指针指向头结点, 体现"循环"
free(Temp); // 释放结点内存, 防止内存泄漏
return true;
}
// 3.如果单向循环链表为非空,需要让尾结点的next指针指向新的首结点(原首结点的直接后继)
while (Phead->next) // 不断向下检查结点指针域
{
Phead = Phead->next; // 进入下一个结点
if (Phead->next == Head->next) // 当到达尾结点
{
break;
}
}
Phead->next = Head->next->next; // 让尾结点的next指针指向新的首结点(原首结点的直接后继)
Head->next = Phead->next; // 头结点的指针域 修改链接为 新的首结点
Temp->next = NULL; // 让旧的首结点的指针域指向NULL, 从链表中断开, 且防止野指针和内存泄漏
free(Temp); // 释放旧首结点的内存, 防止内存泄漏
return true;
}
/**
* @name CircLList_DestDel
* @brief 中删, 删除某个元素结点
* @param Head 头指针
* @param dest 要删除的目标元素
* @return 程序执行成功与否
* @retval false 删除失败, 未找到目标元素结点
* @retval true 删除成功
* @date 2024/04/25
* @version 1.1
* @note
*/
bool CircLList_DestDel(CircLList_t *Head, DataType_t dest)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
CircLList_t *Prev = Head; // 操作指针 存放当前操作指针的前一个结点地址
// 1.判断单向循环链表是否为空,如果为空,则报错
if (Head == Head->next)
{
printf("Error, CircularLinkList is empty! \n");
return false;
}
// 2.若单向循环链表非空
// 目标结点是首结点, 不再继续查找. 目标结点非首结点, 继续向下查找
while (Current->data != dest)
{
Prev = Current; // 备份Current的前一个位置
Current = Current->next; // 进入下一个结点
if ((Current->next == Head->next) && (Current->data != dest)) // 达到末尾 且 末尾不是目标
{
printf("The target doesn't exist! \n");
return false;
}
} // 找到目标结点, Current此时指向目标 Prev为Current 的前一个位置
// 目标结点是首结点
if (Current == Head->next)
{
// 若链表只有首结点
if (Current->next == Head->next)
{
Head->next = Head; // 空链表状态
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
while (Prev->next) // 不断向下检查结点指针域
{
Prev = Prev->next; // 进入下一个结点
if (Prev->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Prev到达未尾结点
Prev->next = Current->next; // 更新尾结点指针域为新首结点地址
Head->next = Current->next; // 更新首结点链接新首结点
}
else if (Current->next == Head->next) // 目标结点是尾结点
{
Prev->next = Head->next; // 新尾结点链接首结点, 行成循环
}
else // 目标结点是中间结点
{
Prev->next = Current->next;
}
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
/**
* @name CircLList_TailDel
* @brief 删除尾结点
* @param Head 头指针
* @return 程序执行成功与否
* @retval false 删除失败, 链表为空
* @retval true 删除成功
* @date 2024/04/25
* @version 1.0
* @note
*/
bool CircLList_TailDel(CircLList_t *Head)
{
CircLList_t *Current = Head->next; // 操作指针 初始为指向首结点, 若为空链表则指向头结点
CircLList_t *Prev = Head; // 操作指针 存放当前操作指针的前一个结点地址
// 1.判断单向循环链表是否为空,如果为空,则报错
if (Head == Head->next)
{
printf("Error, CircularLinkList is empty! \n");
return false;
}
// 2.若单向循环链表非空
// 若链表只有首结点
if (Current->next == Head->next)
{
Head->next = Head; // 空链表状态
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
// 若还有别的结点
while (Current->next) // 不断向下检查结点指针域
{
Prev = Current;
Current = Current->next; // 进入下一个结点
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
} // Current到达未尾结点 Prev为Current 的前一个位置
Prev->next = Head->next; // 新尾结点链接首结点, 行成循环
Current->next = NULL;
free(Current); // 防止内存泄漏
return true;
}
/**
* @name CircLList_Print
* @brief 从头到尾遍历链表
* @param Head 头指针
* @return 无
* @date 2024/04/23
* @version 1.0
* @note
*/
void CircLList_Print(CircLList_t *Head)
{
// 判断是否为空链表
if (Head->next == Head)
{
printf("The list is empty.\n");
return;
}
CircLList_t *Current = Head->next; // 指向首结点
printf("Circular Linked List: ");
while (Current->next) // 不断向下检查结点指针域
{
printf(" -> %d", Current->data); // 打印结点数据
if (Current->next == Head->next) // 结束条件: 达尾结点
{
break;
}
Current = Current->next; // 进入下一个结点
}
printf("\n"); // 刷新行缓冲, 输出缓冲区
}
projecttesting.c
/**
* @file name : projecttesting.c
* @brief : 实现单向循环链表的相关功能测试
* @author :RISE_AND_GRIND@163.com
* @date :2024/04/25
* @version :1.1
* @note :
* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd
*/
#include "CircularLinkedList.h"
int main(int argc, char const *argv[])
{
// 创建单向循环链表, 空链表
CircLList_t *Manager = CircLList_Create();
// 头插法 向链表中插入新结点
printf("*********************************CircLList_HeadInsert********************************\n");
CircLList_HeadInsert(Manager, 7);
CircLList_HeadInsert(Manager, 4);
CircLList_HeadInsert(Manager, 1);
CircLList_HeadInsert(Manager, 8);
CircLList_HeadInsert(Manager, 5);
CircLList_HeadInsert(Manager, 2);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 5 -> 8 -> 1 -> 4 -> 7*/
// 中插法 向链表中插入新结点
printf("*********************************CircLList_DestInsert********************************\n");
CircLList_DestInsert(Manager, 7, 9);
CircLList_DestInsert(Manager, 4, 6);
CircLList_DestInsert(Manager, 2, 3);
CircLList_DestInsert(Manager, 5, 10);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9*/
// 尾插法 向链表中插入新结点
printf("*********************************CircLList_TailInsert********************************\n");
CircLList_TailInsert(Manager, 13);
CircLList_TailInsert(Manager, 12);
CircLList_TailInsert(Manager, 11);
CircLList_Print(Manager);
/*Circular Linked List: -> 2 -> 3 -> 5 -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11*/
// 头删法 删除首结点
printf("*********************************CircLList_HeadDel********************************\n");
CircLList_HeadDel(Manager);
CircLList_HeadDel(Manager);
CircLList_HeadDel(Manager);
CircLList_Print(Manager);
/*Circular Linked List: -> 10 -> 8 -> 1 -> 4 -> 6 -> 7 -> 9 -> 13 -> 12 -> 11*/
// 中删法 删除指定结点
printf("*********************************CircLList_DestDel********************************\n");
CircLList_DestDel(Manager, 10);
CircLList_DestDel(Manager, 1);
CircLList_DestDel(Manager, 6);
CircLList_DestDel(Manager, 11);
CircLList_Print(Manager);
/*Circular Linked List: -> 8 -> 4 -> 7 -> 9 -> 13 -> 12*/
// 尾删法 删除尾结点
printf("*********************************CircLList_HeadDel********************************\n");
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_Print(Manager);
/*Circular Linked List: -> 8 -> 4*/
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
CircLList_TailDel(Manager);
/*Error, CircularLinkList is empty! */
CircLList_HeadInsert(Manager, 66);
CircLList_Print(Manager);
/*Circular Linked List: -> 66*/
// 等待用户响应
printf("***Press any key to exit the test***\n");
getchar();
return 0;
}
本文来自博客园,作者:舟清颺,转载请注明原文链接:https://www.cnblogs.com/zqingyang/p/18158444