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

单向循环链表的使用

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
============修改后的节点============
*/
相关推荐
egoist20231 小时前
【C++指南】一文总结C++二叉搜索树
开发语言·数据结构·c++·c++11·二叉搜索树
lidashent1 小时前
数据结构和算法——汉诺塔问题
数据结构·算法
ん贤4 小时前
2023第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(真题&题解)(C++/Java题解)
java·c语言·数据结构·c++·算法·蓝桥杯
梭七y4 小时前
【力扣hot100题】(022)反转链表
算法·leetcode·链表
我的sun&shine10 小时前
高级数据结构03RB树
数据结构·b树
_GR13 小时前
2022年蓝桥杯第十三届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·蓝桥杯·动态规划
快来卷java13 小时前
常见集合篇(二)数组、ArrayList与链表:原理、源码及业务场景深度解析
java·数据结构·链表·maven
Stardep14 小时前
算法学习11——滑动窗口——最大连续1的个数
数据结构·c++·学习·算法·leetcode·动态规划·牛客网
rigidwill66615 小时前
LeetCode hot 100—二叉搜索树中第K小的元素
数据结构·c++·算法·leetcode·职场和发展
UP_Continue19 小时前
排序--归并排序
数据结构