数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

这篇具有很好参考价值的文章主要介绍了数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于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
 */

目录

目录
  • 目录
  • 单向循环链表公式
  • 初始化单向循环链表
    • 构建单向循环链表结点
    • 创建一个空链表(仅头结点)
    • 创建一个新结点
  • 插入数据
    • 头插
    • 中插
    • 尾插
  • 删除数据
    • 头删
    • 中删
    • 尾删
  • 查询打印数据
    • 遍历打印
  • 测试
    • 测试结果:
  • 完整代码
    • CircularLinkedList.h
    • CircularLinkedList.c
    • projecttesting.c

单向循环链表公式

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * 声明单循环链表的结点
 *
 * 单向循环链表总结成公式
 *     struct xxx
 *     {
 *         //数据域(需要存放什么类型的数据,你就定义对应的变量即可)
 *         //指针域(直接后继的指针域)
 *     };
 *   单向循环链表的基本操作:
 *     初始化单向循环链表 √
 *     插入数据 √
 *     删除数据 √
 *     修改数据
 *     查询打印数据√
 */

初始化单向循环链表

构建单向循环链表结点

CircLList_t[ data |*next ]

// 指的是单向循环链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;

// 构造单向循环链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct CircularLinkedList
{
    DataType_t data;                 // 结点的数据域
    struct CircularLinkedList *next; // 直接后继的指针域
} CircLList_t;

创建一个空链表(仅头结点)

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

创建一个新结点

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

插入数据

头插

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

中插

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

尾插

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

删除数据

头删

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

中删

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

/**
 * @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;
}

尾删

数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)文章来源地址https://www.toymoban.com/news/detail-858002.html

/**
 * @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;
}

到了这里,关于数据结构_链表_单向循环链表的初始化、插入、删除、修改、查询打印(基于C语言实现)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【数据结构C/C++】单向链表的增删改查

    单向链表是比较常用的数据结构,最近再面试手撕算法的时候偶尔有遇到,所以就花了一点时间简单的写了一下C/C++版本的单向链表的代码。 这里我推荐使用C++版本,因为C++版本我特地优化了一下,提供了用户输入的功能,当然两个语言差异不大,注释可以直接看C版本的,比

    2024年02月07日
    浏览(9)
  • 数据结构入门(C语言版)线性表中链表介绍及无头单向非循环链表接口实现

    数据结构入门(C语言版)线性表中链表介绍及无头单向非循环链表接口实现

    概念 : 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素 。因此,为了表示每个数据元素与其直接后继数据元素之间的逻辑关系,对数据元素来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这

    2023年04月09日
    浏览(13)
  • 【数据结构】链表:带头双向循环链表的增删查改

    【数据结构】链表:带头双向循环链表的增删查改

    本篇要分享的内容是带头双向链表,以下为本片目录 目录 一、链表的所有结构 二、带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除  2.7查找结点 2.8任意位置插入 2.9任意位置删除  在刚开始接触链表的时候,我们所学仅仅所学的

    2024年02月05日
    浏览(12)
  • 【数据结构】—带头双向循环链表的实现(完美链表)

    【数据结构】—带头双向循环链表的实现(完美链表)

    链表结构一共有八种形式,在前面的文章里已经讲完了不带头单向非循环链表的实现,但是我们发现该链表实现尾插与尾删时比较麻烦,要先从头节点进行遍历,找到尾节点,时间复杂度为O(N),而本次所讲的带头双向循环单链表,则可以直接找到尾节点。 虽然该链表看起来

    2024年01月25日
    浏览(9)
  • 数据结构:链表基础OJ练习+带头双向循环链表的实现

    数据结构:链表基础OJ练习+带头双向循环链表的实现

    目录 一.leetcode剑指 Offer II 027. 回文链表 1.问题描述 2.问题分析与求解 (1) 快慢指针法定位链表的中间节点 (2) 将链表后半部分进行反转 附:递归法反转链表 (3) 双指针法判断链表是否回文 二.带头双向循环链表的实现 1.头文件 2.节点内存申请接口和链表初始化接口 3.链表的打

    2024年02月02日
    浏览(15)
  • 【数据结构】单向链表的增删查改以及指定pos位置的插入删除

    【数据结构】单向链表的增删查改以及指定pos位置的插入删除

    目录  单向链表的概念及结构  尾插 头插 尾删 ​编辑  头删  查找  在pos位置前插  在pos位置后插  删除pos位置  删除pos的后一个位置 总结 代码  概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表中的 指针链接 次序实现的

    2024年02月05日
    浏览(12)
  • 【玩转408数据结构】线性表——双链表、循环链表和静态链表(线性表的链式表示 下)

    【玩转408数据结构】线性表——双链表、循环链表和静态链表(线性表的链式表示 下)

            在前面的学习中,我们已经了解到了链表(线性表的链式存储)的一些基本特点,并且深入的研究探讨了单链表的一些特性,我们知道,单链表在实现插入删除上,是要比顺序表方便的,但是,单链表中每个结点仅存在一个指针指向其后续结点,那么如果我们想要找

    2024年04月10日
    浏览(40)
  • 数据结构 模拟实现LinkedList单向不循环链表

    数据结构 模拟实现LinkedList单向不循环链表

    目录 一、链表的简单介绍 二、链表的接口 三、链表的方法实现 (1)display方法 (2)size得到单链表的长度方法 (3)addFirst头插方法 (4)addLast尾插方法 (5)addIndex指定位置插入方法 (6)contains方法 (7)remove删除第一个key值节点的方法 (8)removeAllKey删除所有值为key的方法

    2024年02月03日
    浏览(13)
  • 数据结构单向循环链表,创建以及增删改查的实现

    数据结构单向循环链表,创建以及增删改查的实现

    循环链表: 是另一种形式的链式存储结构。其特点是表中最后一个结点的指针域指向头节点,整个链表形成一个环。 单向循环链表的操作和单链表操作基本一致,差别在于:当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同。在单链表中,判别条件一般为p!=

    2024年02月16日
    浏览(13)
  • 四、数据结构——单向链表的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表

    四、数据结构——单向链表的基本操作详解:创建、插入(头插法、尾插法、任意点插法)、删除(头删法、尾删法、任意位置删法)、查询(按值查下标、按下标查值)、遍历链表和清空链表

    ————后面附有全部代码———— 数据结构在计算机科学中扮演着重要角色,它用于组织和管理数据,提高数据的操作和访问效率。单向链表是一种简单但非常重要的数据结构。本文将深入探讨单向链表的定义、特点、基本操作。 单向链表是一种线性数据结构,由一系列

    2024年01月17日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包