当前位置: 首页 > article >正文

【数据结构】单向循环链表的使用

单向循环链表的使用

    • 1、单向循环链表
      • a、初始化单向循环链表
      • b、节点头插
      • c、节点尾插
      • d、节点中间插入
      • e、删除节点
      • f、修改节点
      • g、遍历链表,打印节点数据
    • 2、完整代码

1、单向循环链表

\quad 单向循环链表指得是将链表末尾节点循环地指向链表表头。比如,单向链表变成循环链表的示意图如下所示:
在这里插入图片描述
循环链表的操作跟普通链表操作基本上是一致的,只要针对循环特性稍作修改即可,遍历查找节点时,需将遍历的指针指向头节点。比如:

a、初始化单向循环链表

single_list_t *single_list_init()
{
    single_list_t *head_node = malloc(sizeof(single_list_t));
    head_node->next = head_node; // 指向头节点

    return head_node;
}

b、节点头插

int insert_list_head(int newdata, single_list_t *list)
{
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;

    // 插入节点
    new_node->next = list->next;
    list->next = new_node;

    return 0;
}

c、节点尾插

int insert_list(int newdata, single_list_t *list)
{
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    
    // 定义指针p去找到链表的尾部
    single_list_t *p = list;
    // 单向循环链表中遍历到最后一个节点的next指向头节点时 ,说明该节点是最末尾节点
    while (p->next != list) 
    {
        p = p->next;
    }
    // 此时p已经到最后一个节点的位置
    p->next = new_node;
    new_node->next = list;

    return 0;
}

d、节点中间插入

int insert_list_mid(int olddata, int newdata, single_list_t *list)
{
    // 找到要插入的节点
    single_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
        if (p->data == olddata)
        {
            break;
        }
    }
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    // p指向最后一个节点
    if (p->next == list)
    {
        if (p->data == olddata)
        {
            new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
            p->next = new_node;   // 再将该节点指向新增加的节点
        }
        else
        {
            printf("要插入的数据不存在\n");
            return -1;
        }
    }
    else // 遍历到中间找到需要插入的节点
    {
        new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
        p->next = new_node;   // 再将该节点指向新增加的节点
        
    }
    return 0;
}

e、删除节点

int list_delnode(int deldata, single_list_t *list)
{
    // 定义两个指针去遍历查找要删除的节点
    single_list_t *q = list;
    single_list_t *p = list->next;
    while (p->next != list)
    {
        // 找到要删除的节点并进行删除
        if (p->data == deldata)
        {
            // 找到后马上删除该节点
            q->next = p->next;  // 将q指向的节点指向被删除节点的下一个节点
            p->next = NULL;     // p节点的next指针指向NULL
            free(p);            // 释放p后此时p是野指针
            p = q->next;        // 将p指向被删除节点的下一个节点
        }
        else
        {
            p = p->next;
            q = q->next;
        }  
    }
    // 遍历到最后一个节点
    if (p->next == list)
    {
        // 若最后一个节点是要删除的节点,则删除
        if (p->data == deldata)
        {
            q->next = p->next;
            p->next = NULL;
            free(p);
        }
        else
        {
            printf("最后一个节点不是要删除的节点\n");
            return 0;
        }
    }
}

f、修改节点

int list_update_node(int old_data, int new_data, single_list_t *list)
{
    single_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;  // p往后移动
        if (p->data == old_data)
        {
            p->data = new_data;
        }
    }
    return 0;
}

g、遍历链表,打印节点数据

int list_show(single_list_t *list)
{
    // //定义指针p遍历链表
    single_list_t *p = list;

    while (p->next != list)
    {
        p = p->next;  // p往后挪动
        printf("当前p指向的节点数据:%d\n", p->data);
    }
}

2、完整代码

#include <stdio.h>
#include <stdlib.h>

// 1.封装一个结构体来表示单链表
typedef struct single_list{
    int data;
    struct single_list *next;
}single_list_t;

/*@brief:2.初始化单链表-->定义结构体变量 创建头节点
 *@param(in):  none
 *@param(out):  none
 *@retval:    head_node 头节点
*/
single_list_t *single_list_init()
{
    single_list_t *head_node = malloc(sizeof(single_list_t));
    head_node->next = head_node; // 指向头节点

    return head_node;
}
// 头插
int insert_list_head(int newdata, single_list_t *list)
{
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;

    // 插入节点
    new_node->next = list->next;
    list->next = new_node;

    return 0;
}

/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)
 *@param(in):  newdata :待插入的数据  
                list:待插入的链表
 *@param(out):  none
 *@retval:    none
*/
int insert_list(int newdata, single_list_t *list)
{
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    
    // 定义指针p去找到链表的尾部
    single_list_t *p = list;
    // 单向循环链表中遍历到最后一个节点的next指向头节点时 ,说明该节点是最末尾节点
    while (p->next != list) 
    {
        p = p->next;
    }
    // 此时p已经到最后一个节点的位置
    p->next = new_node;
    new_node->next = list;

    return 0;
}

/*@brief:3.插入数据-->中间插入
 *@param(in):  newdata :待插入的数据
                olddata:在该节点后插入数据
                list:待插入的链表
 *@param(out):  none
 *@retval:    none
*/
int insert_list_mid(int olddata, int newdata, single_list_t *list)
{
    // 找到要插入的节点
    single_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
        if (p->data == olddata)
        {
            break;
        }
    }
    // 申请一个节点 -堆空间
    single_list_t *new_node = malloc(sizeof(single_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    // p指向最后一个节点
    if (p->next == list)
    {
        if (p->data == olddata)
        {
            new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
            p->next = new_node;   // 再将该节点指向新增加的节点
        }
        else
        {
            printf("要插入的数据不存在\n");
            return -1;
        }
    }
    else // 遍历到中间找到需要插入的节点
    {
        new_node->next = p->next; // 先让新增加的节点指向找到节点的下一个节点
        p->next = new_node;   // 再将该节点指向新增加的节点
        
    }
    return 0;
}

/*@brief:3.删除节点
 *@param(in):  deldata :待删除的节点
                list:待插入的链表
 *@param(out):  none
 *@retval:    none
*/
int list_delnode(int deldata, single_list_t *list)
{
    // 定义两个指针去遍历查找要删除的节点
    single_list_t *q = list;
    single_list_t *p = list->next;
    while (p->next != list)
    {
        // 找到要删除的节点并进行删除
        if (p->data == deldata)
        {
            // 找到后马上删除该节点
            q->next = p->next;  // 将q指向的节点指向被删除节点的下一个节点
            p->next = NULL;     // p节点的next指针指向NULL
            free(p);            // 释放p后此时p是野指针
            p = q->next;        // 将p指向被删除节点的下一个节点
        }
        else
        {
            p = p->next;
            q = q->next;
        }  
    }
    // 遍历到最后一个节点
    if (p->next == list)
    {
        // 若最后一个节点是要删除的节点,则删除
        if (p->data == deldata)
        {
            q->next = p->next;
            p->next = NULL;
            free(p);
        }
        else
        {
            printf("最后一个节点不是要删除的节点\n");
            return 0;
        }
    }
}
// 修改节点
int list_update_node(int old_data, int new_data, single_list_t *list)
{
    single_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;  // p往后移动
        if (p->data == old_data)
        {
            p->data = new_data;
        }
    }
    return 0;
}

// 4.遍历链表,打印节点数据
int list_show(single_list_t *list)
{
    // //定义指针p遍历链表
    single_list_t *p = list;

    while (p->next != list)
    {
        p = p->next;  // p往后挪动
        printf("当前p指向的节点数据:%d\n", p->data);
    }
}

int main(int argc, char const *argv[])
{
    // 初始化单链表
    single_list_t *my_list = single_list_init();
    // 往链表插入数据
    insert_list(15, my_list);
    insert_list(18, my_list);
    insert_list(15, my_list);
    insert_list(25, my_list);
    insert_list(666, my_list);
    insert_list(123, my_list);
    insert_list(11111111, my_list);
    insert_list_mid(666, 777, my_list);
    insert_list_mid(1, 222, my_list);
    insert_list_head(999, my_list);
    insert_list_head(888, my_list);
 

    printf("============插入的节点============\n");
    list_show(my_list);
    printf("============插入的节点============\n");
    // 删除节点
    list_delnode(25,my_list);
    printf("============删除后的节点============\n");
    list_show(my_list); // 打印数据
    printf("============删除后的节点============\n");
    // 修改数据
    list_update_node(123, 234, my_list);
    printf("============修改后的节点============\n");
    list_show(my_list); // 打印数据
    printf("============修改后的节点============\n");

    return 0;
}
/*
执行结果:
要插入的数据不存在
============插入的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:25
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============插入的节点============
最后一个节点不是要删除的节点
============删除后的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:123
当前p指向的节点数据:11111111
============删除后的节点============
============修改后的节点============
当前p指向的节点数据:888
当前p指向的节点数据:999
当前p指向的节点数据:15
当前p指向的节点数据:18
当前p指向的节点数据:15
当前p指向的节点数据:666
当前p指向的节点数据:777
当前p指向的节点数据:234
当前p指向的节点数据:11111111
============修改后的节点============
*/

http://www.kler.cn/a/461229.html

相关文章:

  • 【可实战】需求分析-测试计划↓-测试设计-测试执行-测试总结↓(包含测试计划、测试总结模板,以公司要求为准)
  • 弧形导轨如何避免生锈?
  • Unity3D ILRuntime开发原则与接口绑定详解
  • 图书项目:整合SSM
  • 网工日记:FTP两种工作模式的区别
  • 网络安全态势感知
  • 01-2023年上半年软件设计师考试java真题解析
  • 小程序 手写tab超出滑动。view超出可以横滑动
  • Kafka高性能设计
  • 手写顺序流程图组件
  • Windows onnxruntime编译openvino
  • 部分开源数据整理
  • win32汇编环境下,对话框程序中生成listview列表控件,点击标题栏自动排序的示例
  • STM32 高级 物联网通讯之LoRa通讯
  • SNIPE-IT详细安装教程(已安装成功)
  • RabbitMQ - 2 ( 21000 字 RabbitMQ 入门级教程 )
  • Android学习小记3
  • 耳切法简述
  • 矩阵的因子分解3-LU分解和LDU分解
  • WebSocket 入门详解
  • 【每日学点鸿蒙知识】Taro、native层获取文件宽度、位置变化callback、数据迁移、oh_modules说明等
  • QT--多线程
  • 深入浅出 Spring (二)| 依赖注入(DI)、自动装配
  • 课程思政元素收集系统|Java|SSM|JSP|
  • 计算机网络基础知识(7)中科大郑铨老师笔记
  • 【视觉SLAM:四、相机与图像】