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

单向循环链表的使用

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
============修改后的节点============
*/
相关推荐
被AI抢饭碗的人2 小时前
算法题(56):旋转链表
数据结构·算法·链表
守正出琦2 小时前
从零开始实现一个双向循环链表:C语言实战
c语言·数据结构·链表
CPU NULL4 小时前
【蓝桥杯】日志统计
数据结构·c++·算法·蓝桥杯
zm4 小时前
C基础寒假练习(2)
数据结构·算法
和风化雨4 小时前
排序算法--希尔排序
c语言·数据结构·c++·算法·排序算法
sjsjs115 小时前
【数据结构-Trie树】力扣677. 键值映射
数据结构·算法·leetcode
一只自律的鸡5 小时前
数据结构 前缀中缀后缀
数据结构
励志成为美貌才华为一体的女子5 小时前
python算法和数据结构刷题[6]:二叉树、堆、BFS\DFS
数据结构·算法
wclass-zhengge5 小时前
04树 + 堆 + 优先队列 + 图(D1_树(D10_决策树))
数据结构·算法
Victoria.a10 小时前
string类详解
数据结构·c++