关于单向循环链表的创建、插入、删除、遍历

关于单向循环链表的创建、插入、删除、遍历、

单向循环链表的公式

image

单向循环链表的代码

#include <stdio.h>       // 标准输入输出头文件
#include <string.h>      // 字符串处理头文件        memset/清空
#include <stdlib.h>      // 标准库头文件            malloc/申请堆空间
#include <unistd.h>      // sleep延时


//宏定义数据
#define DATA_LEN 20
#define SEARCH_MODE_PRESENT 1 //找当前
#define SEARCH_MODE_BEFOR   2 //上一个

//定义结构体类型
typedef struct loop_link_node
{
    //数据域
    char data[DATA_LEN];
    //指针域
    struct loop_link_node * next;
}LOOP_LINK_NODE,*P_LINK;


/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 函数声明文件 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */


P_LINK Create_New_Node();                                       // 声明一个创建新节点的函数
P_LINK Retrieve_Add_Node(P_LINK head_node,int search_mode);     // 声明一个目标检索函数
int Mode_Selection(P_LINK head_node);                           // 声明一个功能选择函数,检测链表各种模式
int Head_Add_Node(P_LINK head_node);                            // 声明一个头插函数
int Ergodic_List_Node(P_LINK head_node);                        // 声明一个遍历函数
int Tail_Add_Node(P_LINK head_node);                            // 声明一个尾插函数
int Appoint_Add_Node(P_LINK head_node);                         // 声明一个指定位置插入函数
int Del_Add_Node(P_LINK head_node);                             // 声明一个指定位置删除函数


/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 函数声明文件 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */

// 定义一个函数,来创建一个新节点
P_LINK Create_New_Node()
{
    //申请新节点的内存空间
    P_LINK new_node = (P_LINK)malloc(sizeof(LOOP_LINK_NODE));
    if(new_node == (P_LINK)NULL)//检查内存是否申请成功
    {
        perror("malloc ...");
        return (P_LINK)-1;
    }

    //清空
    memset(new_node,0,sizeof(LOOP_LINK_NODE));

    //新节点的指针指向自己,体现循环
    new_node->next = new_node;

    return new_node; //返回申请的新节点
}


// 创建一个功能函数用来进行检测操作链表的插入、删除、遍历、检索
int Mode_Selection(P_LINK head_node)
{
    // 如果头节点为空,输出提示信息并返回错误码
    if (head_node == (P_LINK)NULL)
    {
        printf("头节点为空!\n");
        return -1;
    }

    int select_num; // 用于存放用户输入的选择编号
    while (1)       // 无限循环,直到用户选择退出
    {
        system("clear"); // 清屏

        // 显示菜单项
        printf("<<<< 1 头插添加数据节点 >>>>\n");
        printf("<<<< 2 尾插添加数据节点 >>>>\n");
        printf("<<<< 3 指定检索数据节点 >>>>\n");
        printf("<<<< 4 指定添加数据节点 >>>>\n");
        printf("<<<< 5 指定删除数据节点 >>>>\n");
        printf("<<<< 6 遍历链表数据节点 >>>>\n");
        printf("<<<< 7 退出单向循环链表 >>>>\n");

        // 获取用户的指令输入
        scanf("%d", &select_num);

        // 根据用户选择进行相应的操作
        switch (select_num)
        {
            case 1:Head_Add_Node(head_node);break;                          // 头插法添加数据节点
            case 2:Tail_Add_Node(head_node);break;                          // 尾插法添加数据节点
            case 3:Retrieve_Add_Node(head_node,SEARCH_MODE_PRESENT);break;  // 检索目标数据节点并返回
            case 4:Appoint_Add_Node(head_node);break;                       // 目标位置添加数据节点
            case 5:Del_Add_Node(head_node);break;                           // 指定位置删除节点 
            case 6:Ergodic_List_Node(head_node);break;                      // 遍历整个链表并输出显示
            case 7:return 0;                                                // 退出单向循环链表
            default:printf("没有此项指令,请重新输入!\n");break;              // 输入无效,提示重新输入
        }
        sleep(1); // 延时1秒,使用户能看到执行结果
    }

    return 0;
}

//头插法,插入链表
int Head_Add_Node(P_LINK head_node)
{
    //判断头节点是否异常
    if(head_node == (P_LINK)NULL)
    {
        printf("head node abnormal");
        return -1;
    }

    //创建新节点
    P_LINK new_node = Create_New_Node();
    if(new_node == (P_LINK)NULL)
    {
        printf("Create new node faile");
        return -1;
    }

    printf("输入待插入的数据:");
    scanf("%s",new_node->data);
    while(getchar() !='\n');   // 清空输入缓冲区

    new_node->next = head_node->next; //新节点的下一个指针指向头节点的下一个的指针
    head_node->next = new_node;       //新节点的下一个指向新节点

    printf("头插成功!数据:%s----地址:%p\n",new_node->data,new_node);

    return 0;
}

// 定义函数 Tail_Add_Node,用于在单向循环链表中尾部位置删除节点
int Tail_Add_Node(P_LINK head_node)
{
    //判断头节点是否异常
    if(head_node == (P_LINK)NULL)
    {
        printf("head node abnormal\n");
        return -1;
    }

    //创建新节点
    P_LINK new_node = Create_New_Node();
    if(new_node == (P_LINK)NULL)
    {
        printf("Create new node faile");
        return -1;
    }

    //输入尾插数据
    printf("输入尾插数据:");
    scanf("%s",new_node->data);
    while(getchar() != '\n'); //清空输入缓冲区

    //声明尾节点变量
    P_LINK end_node;
    //遍历找到尾节点
    for(end_node = head_node; end_node->next != head_node; end_node = end_node->next);

    new_node->next = end_node->next; //新节点的下一个指针指向尾节点的下一个
    end_node->next = new_node;       //尾节点的下一个指针指向新节点

    printf("尾插成功!数据:%s----地址:%p\n",new_node->data,new_node);
    return 0;
}

//检索整个链表
P_LINK Retrieve_Add_Node(P_LINK head_node,int search_mode)
{
    //判断头节点是否异常
    if(head_node == (P_LINK)NULL)
    {
        printf("head node abnormal\n");
        return (P_LINK)-1;
    }
    //判断是否是空链表
    if(head_node->next == head_node)
    {
        printf("空链表,无需检索!\n");
        return (P_LINK)0;
    }

    //定义目标数据节点
    char obj_data[DATA_LEN]="\0";
    printf("输入目标数据:");
    scanf("%s",obj_data);

    //循环遍历找目标节点
    for(P_LINK tmp_node = head_node; tmp_node->next != head_node; tmp_node = tmp_node->next)
    {
        //如果成立,则tmp_node就是上一个结点
        if(strcmp(tmp_node->next->data,obj_data) == 0)
        {
            printf("找到该节点:数据:%s---地址:%p\n",tmp_node->next->data,tmp_node->next);

            if(search_mode == SEARCH_MODE_PRESENT)  // 判断是否临时节点的下一个节点
            {
                return tmp_node->next;              // 返回临时节点的下一个节点
            }
            if(search_mode == SEARCH_MODE_BEFOR)    // 判断是否临时节点
            {
                return tmp_node;                    // 返回临时节点
            }
        }
    }

    return (P_LINK)0;
}

// 定义函数 Appoint_Add_Node,用于在单向循环链表中指定位置插入新节点
int Appoint_Add_Node(P_LINK head_node)
{
    //判断头节点异常
    if(head_node == NULL)
    {
        printf("头节点异常!\n");
        return -1;
    }
    //判断链表是否为空
    else if(head_node->next == head_node)
    {
        printf("空链表默认尾插!\n");
        if(Tail_Add_Node(head_node) == -1)
        {
            printf("默认头插失败!\n");
            return -1;
        }
    }
    else
    {
        //创建目标节点
        P_LINK obj_node = Retrieve_Add_Node(head_node,SEARCH_MODE_PRESENT);
        if(obj_node == (P_LINK)-1)
        {
            printf("链表异常!目标节点创建失败!\n");
            return -1;
        }
        //判断是否有目标节点
        else if(obj_node == (P_LINK)0)
        {
            printf("没有找到目标节点!\n");
            return 0;
        }
        //找到目标节点进行插入
        else
        {
            //创建新节点
            P_LINK new_node = Create_New_Node();
            if(new_node == (P_LINK)NULL)
            {
                printf("创建新节点失败!\n");
                return -1;
            }

            printf("输入插入的数据:");
            // 从标准输入读取新节点数据
            scanf("%s",new_node->data);
            while(getchar() !='\n');// 清空输入缓冲区

            //调整指针指向,完成插入
            new_node->next = obj_node->next;  //新节点的下一个指针指向目标节点的下一个
            obj_node->next = new_node;        //目标节点的下一个指向新节点

            printf("指定插入完成!\n");
        }

    }

    return 0;
}

// 定义函数 Del_Add_Node,用于删除单向循环链表中的指定节点
int Del_Add_Node(P_LINK head_node)
{
    //判断头节点是否异常
    if(head_node == NULL)
    {
        printf("链表异常!\n");
        return -1;
    }
    //判断是否是空链表
    else if(head_node->next == head_node)
    {
        printf("空链表无需删除!\n");
        return -1;
    }
    else
    {
        //检索被删除的上一个节点
        P_LINK before_del_node = Retrieve_Add_Node(head_node,SEARCH_MODE_BEFOR);
        if(before_del_node == (P_LINK)-1)
        {
            printf("链表异常,无法删除!\n");
            return -1;
        }
        //判断是否有要删除的节点数据
        else if(before_del_node == (P_LINK)0)
        {
            printf("未找到要删除的目标节点!\n");
            return 0;
        }
        else
        {
            //找到删除节点,进行删除操作
            printf("数据的删除:");
            //创建被删除的节点
            P_LINK del_node       = before_del_node->next; //被删除节点的上一个指向的创建的被删除的节点
            before_del_node->next = del_node->next;        //被删除节点的上一个指向被删除节点的下一个指针
            del_node->next        = NULL;                  //被删除的节点指针指向空

            printf("删除节点成功!\n");
            //释放删除节点空间
            free(del_node);
            return 0;
        }

    }
}

// 定义函数 Ergodic_List_Node,用于遍历单向循环链表并在用户终端显示
int Ergodic_List_Node(P_LINK head_node)
{
    //判断头节点是否异常
    if(head_node == (P_LINK)NULL)
    {
        printf("head node abnormal");
        return -1;
    }
    //判断是不是空链表
    else if(head_node->next == head_node)
    {
        printf("空链表,无需遍历!\n");
        return 0;
    }
    else
    {
        //循环遍历输出显示地址与插入的数据
        for(P_LINK tmp_node = head_node->next; tmp_node->next != head_node->next; tmp_node = tmp_node->next)
        {
            printf("数据:%s----地址:%p\n",tmp_node->data,tmp_node);
        }
    }


    return 0;
}


int main()
{
    //创建一个头节点
    P_LINK head_node = Create_New_Node();
    if(head_node == (P_LINK)NULL)//判断单向循环链表是否创建成功
    {
        printf("创建单向循环链表失败!\n");
        return -1;
    }
    else
    {
        printf("创建单向循环链表成功!\n");
    }

    //调用功能函数
    Mode_Selection(head_node);

    return 0;
}

posted @   待会儿去码头整点薯条  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示