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

单向循环链表的使用

1、单向循环链表

\quad 单向循环链表指得是将链表末尾节点循环地指向链表表头。比如,单向链表变成循环链表的示意图如下所示:

循环链表的操作跟普通链表操作基本上是一致的,只要针对循环特性稍作修改即可,遍历查找节点时,需将遍历的指针指向头节点。比如:

a、初始化单向循环链表

c 复制代码
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、节点头插

c 复制代码
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、节点尾插

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、节点中间插入

c 复制代码
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、删除节点

c 复制代码
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、修改节点

c 复制代码
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、遍历链表,打印节点数据

c 复制代码
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、完整代码

c 复制代码
#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
============修改后的节点============
*/
相关推荐
权^1 小时前
数据结构--顺序表(详解)
数据结构
Bruce_Li_Q1 小时前
算法 Class 006(二分搜索)
数据结构
爱是小小的癌3 小时前
Java-数据结构-顺序表(ArrayList)
java·开发语言·数据结构
egoist20233 小时前
数据结构之单链表(超详解)
c语言·开发语言·数据结构·笔记·学习·链表·gitee
R_.L4 小时前
七大排序算法:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序、归并排序
数据结构·算法·排序算法
TANGLONG2225 小时前
【C++】穿越时光隧道,拾贝史海遗珍,轻启C++入门之钥,解锁程序之奥秘(首卷)
java·c语言·数据结构·c++·redis·python·算法
星迹日5 小时前
数据结构:时间复杂度和空间复杂度
数据结构·算法·时间空间复杂度
go_bai5 小时前
OJ随机链表的复制题目分析
数据结构·经验分享·笔记·链表·学习方法
武昌库里写JAVA5 小时前
Springboot 升级带来的Swagger异常
数据结构·vue.js·spring boot·算法·课程设计
秋凉之夏_惊鸿之羽6 小时前
数据结构-1-线性表
数据结构