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

双向循环链表的使用

1.双向循环链表节点设计

c 复制代码
typedef struct double_list{
    int data;
    struct double_list *next;
    struct double_list *prev;
}double_list_t;

2.初始化双向循环链表-->定义结构体变量 创建头节点

(1)示例代码:

c 复制代码
double_list_t *double_list_init()
{
    double_list_t *head_node = malloc(sizeof(double_list_t));
    if (head_node != NULL)
    {
        head_node->next = head_node;
        head_node->prev = head_node;
    }
    else
    {
        printf("[double_list_init]申请头节点失败\n");
    }
    
    return head_node;
}

(2)图示

3.双向循环链表节点头插

(1)示例代码:

c 复制代码
int insert_list_head(int newdata, double_list_t *list)
{
    // 申请一个节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    if (new_node == NULL) 
    {
        printf("[insert_list_head]申请新的节点失败\n");
        return -1; // 申请内存失败
    }
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // 当链表为空时
    if (list->next == list)
    {
        list->next = new_node;
        new_node->next = list;
        new_node->prev = list;
        list->prev = new_node;
        // printf("[insert_list_head]当链表为空时\n");
    }
    // 链表不为空时
    else
    {
        // 插入节点
        new_node->next = list->next;
        list->next = new_node;
        new_node->next->prev = new_node;
        new_node->prev = list;
        // printf("[insert_list_head]当链表不为空时\n");
    }
    return 0;
}

(2)图示


4.双向循环链表节点尾插

(1)示例代码:

c 复制代码
int insert_list_tail(int newdata, double_list_t *list)
{
    // 申请一个节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    if (new_node == NULL) 
    {
        printf("[insert_list_tail]申请新的节点失败\n");
        return -1; // 申请内存失败
    }

    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // 定义指针p去找到链表的尾部
    double_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
    }
    // 此时p已经到最后一个节点的位置
    new_node->next = list;
    p->next = new_node;
    list->prev = new_node;
    new_node->prev = p;

    return 0;
}

(2)图示

5.双向循环链表节点中间插入

(1)示例代码:

c 复制代码
int insert_list_mid(int olddata, int newdata, double_list_t *list)
{
    // 找到要插入的节点
    double_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
        if (p->data == olddata)
        {
            break;
        }
    }
    // 申请一个新的节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // p指向最后一个节点
    if (p->next == list)
    {
        // 如果最后一个节点是要插入的数据
        if (p->data == olddata)
        {
            new_node->next = p->next; 
            p->next = new_node;  
            new_node->prev = p;
        }
        else
        {
            printf("[insert_list_mid]要插入的数据不存在\n");
            return -1;
        }
    }
    else // 遍历到中间找到需要插入的节点
    {
        new_node->next = p->next; 
        p->next = new_node;   
        new_node->prev = p;   
        new_node->next->prev = new_node;
    }
    return 0;
}

(2)图示

6.双向循环链表删除节点

(1)示例代码:

c 复制代码
int list_delnode(int deldata, double_list_t *list)
{
    // p指向链表的头节点
    double_list_t *p = list;
    while (p->next != list)
    {
        // 找到要删除的节点并进行删除
        if (p->data == deldata)
        {
            p->prev->next = p->next;     
            p->next->prev = p->prev;
            double_list_t *temp = p->next; // 将temp指针指向p的下一个节点 
            p->next = NULL;
            p->prev = NULL;
            free(p);    // 释放p后此时p是野指针
            p = temp;   // p往后移动

        }
        else
        {
            p = p->next;
        }  
    }
    // 遍历到最后一个节点
    if (p->next == list)
    {
        // 若最后一个节点是要删除的节点,则删除
        if (p->data == deldata)
        {
            p->prev->next = list;
            p->next = NULL;
            list->prev = p->prev;
            p->prev = NULL;
            free(p);
        }
        else
        {
            printf("[list_delnode]最后一个节点不是要删除的节点\n");
            return 0;
        }
    }
}

(2)图示


7.双向循环链表修改节点数据

(1)示例代码:

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

8.双向循环链表遍历

c 复制代码
int list_show(double_list_t *list)
{
    double_list_t *p = list; //p指向头结点

    while (p->next != list)
    {
        p = p->next;
        printf("[list_show]当前p指向的节点数据:%d\n", p->data);
    }
}

9.完整示例代码

c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 1.封装一个结构体来表示双向循环链表
typedef struct double_list{
    int data;
    struct double_list *next;
    struct double_list *prev;
}double_list_t;

// 2.初始化双向循环链表-->定义结构体变量 创建头节点
double_list_t *double_list_init()
{
    double_list_t *head_node = malloc(sizeof(double_list_t));
    if (head_node != NULL)
    {
        head_node->next = head_node;
        head_node->prev = head_node;
    }
    else
    {
        printf("[double_list_init]申请头节点失败\n");
    }
    
    return head_node;
}

// 头插
int insert_list_head(int newdata, double_list_t *list)
{
    // 申请一个节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    if (new_node == NULL) 
    {
        printf("[insert_list_head]申请新的节点失败\n");
        return -1; // 申请内存失败
    }
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // 当链表为空时
    if (list->next == list)
    {
        list->next = new_node;
        new_node->next = list;
        new_node->prev = list;
        list->prev = new_node;
        // printf("[insert_list_head]当链表为空时\n");
    }
    // 链表不为空时
    else
    {
        // 插入节点
        new_node->next = list->next;
        list->next = new_node;
        new_node->next->prev = new_node;
        new_node->prev = list;
        // printf("[insert_list_head]当链表不为空时\n");
    }
    return 0;
}
/*@brief:3.插入数据-->尾插(在最后一个有效成员的后面插入数据)
 *@param(in):  newdata :待插入的数据  
                list:链表头节点
 *@param(out):  
 *@retval:    
*/
int insert_list_tail(int newdata, double_list_t *list)
{
    // 申请一个节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    if (new_node == NULL) 
    {
        printf("[insert_list_tail]申请新的节点失败\n");
        return -1; // 申请内存失败
    }

    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // 定义指针p去找到链表的尾部
    double_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
    }
    // 此时p已经到最后一个节点的位置
    new_node->next = list;
    p->next = new_node;
    list->prev = new_node;
    new_node->prev = p;

    return 0;
}

// 节点中间插入链表
int insert_list_mid(int olddata, int newdata, double_list_t *list)
{
    // 找到要插入的节点
    double_list_t *p = list;
    while (p->next != list)
    {
        p = p->next;
        if (p->data == olddata)
        {
            break;
        }
    }
    // 申请一个新的节点 -堆空间
    double_list_t *new_node = malloc(sizeof(double_list_t));
    // 初始化数据域
    new_node->data = newdata;
    new_node->next = NULL;
    new_node->prev = NULL;

    // p指向最后一个节点
    if (p->next == list)
    {
        // 如果最后一个节点是要插入的数据
        if (p->data == olddata)
        {
            new_node->next = p->next; 
            p->next = new_node;  
            new_node->prev = p;
        }
        else
        {
            printf("[insert_list_mid]要插入的数据不存在\n");
            return -1;
        }
    }
    else // 遍历到中间找到需要插入的节点
    {
        new_node->next = p->next; 
        p->next = new_node;   
        new_node->prev = p;   
        new_node->next->prev = new_node;
    }
    return 0;
}
// 删除节点
int list_delnode(int deldata, double_list_t *list)
{
    // p指向链表的头节点
    double_list_t *p = list;
    while (p->next != list)
    {
        // 找到要删除的节点并进行删除
        if (p->data == deldata)
        {
            p->prev->next = p->next;     
            p->next->prev = p->prev;
            double_list_t *temp = p->next; // 将temp指针指向p的下一个节点 
            p->next = NULL;
            p->prev = NULL;
            free(p);    // 释放p后此时p是野指针
            p = temp;   // p往后移动

        }
        else
        {
            p = p->next;
        }  
    }
    // 遍历到最后一个节点
    if (p->next == list)
    {
        // 若最后一个节点是要删除的节点,则删除
        if (p->data == deldata)
        {
            p->prev->next = list;
            p->next = NULL;
            list->prev = p->prev;
            p->prev = NULL;
            free(p);
        }
        else
        {
            printf("[list_delnode]最后一个节点不是要删除的节点\n");
            return 0;
        }
    }
}
// 修改节点
int list_update_node(int old_data, int new_data, double_list_t *list)
{
    double_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(double_list_t *list)
{
    double_list_t *p = list; //p指向头结点

    while (p->next != list)
    {
        p = p->next;
        printf("[list_show]当前p指向的节点数据:%d\n", p->data);
    }
}

int main(int argc, char const *argv[])
{
    // 初始化单链表 ,指向链表的头节点
    double_list_t *my_list_head = double_list_init();
    // 往链表插入数据
    insert_list_head(2, my_list_head);
    insert_list_head(3, my_list_head);
    insert_list_head(4, my_list_head);

    insert_list_tail(15, my_list_head);
    insert_list_tail(16, my_list_head);
    insert_list_tail(17, my_list_head);
    insert_list_head(2, my_list_head);
    insert_list_tail(15, my_list_head);
    insert_list_tail(15, my_list_head);
    insert_list_tail(15, my_list_head);

    insert_list_mid(5, 6, my_list_head);
    insert_list_mid(2, 88, my_list_head);
    insert_list_mid(17, 15, my_list_head);

    printf("============插入的节点============\n");
    list_show(my_list_head);
    printf("============插入的节点============\n");
    // 删除节点
    list_delnode(25, my_list_head);
    list_delnode(15, my_list_head);
    list_delnode(2, my_list_head);

    printf("============删除后的节点============\n");
    list_show(my_list_head); // 打印数据
    printf("============删除后的节点============\n");
    // 修改数据
    list_update_node(16, 116, my_list_head);
    printf("============修改后的节点============\n");
    list_show(my_list_head); // 打印数据
    printf("============修改后的节点============\n");

    return 0;
}
/*
执行结果:
[insert_list_mid]要插入的数据不存在
============插入的节点============
[list_show]当前p指向的节点数据:2
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:2
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
[list_show]当前p指向的节点数据:15
============插入的节点============
[list_delnode]最后一个节点不是要删除的节点
[list_delnode]最后一个节点不是要删除的节点
============删除后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:16
[list_show]当前p指向的节点数据:17
============删除后的节点============
============修改后的节点============
[list_show]当前p指向的节点数据:88
[list_show]当前p指向的节点数据:4
[list_show]当前p指向的节点数据:3
[list_show]当前p指向的节点数据:116
[list_show]当前p指向的节点数据:17
============修改后的节点============
*/
相关推荐
_星辰大海乀5 分钟前
LinkedList 双向链表
java·数据结构·链表·list·idea
星空露珠1 小时前
迷你世界脚本显示板管理接口:DisPlayBoard
数据结构·游戏·lua
商bol451 小时前
算阶,jdk和idea的安装
数据结构·c++·算法
柠檬鲨_4 小时前
C语言100天练习题【记录本】
c语言·数据结构·算法
星空露珠11 小时前
迷你世界脚本聊天接口:Chat
数据结构·游戏·lua
啥都想学的又啥都不会的研究生12 小时前
Redis设计与实现-数据结构
数据结构·数据库·redis·笔记·缓存·性能优化·skiplist
mit6.82412 小时前
[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数
数据结构·c++·算法·leetcode
zjoy_223312 小时前
【数据结构】什么是栈||栈的经典应用||分治递归||斐波那契问题和归并算法||递归实现||顺序栈和链栈的区分
java·c语言·开发语言·数据结构·c++·算法·排序算法
油泼辣子多加13 小时前
【华为OD机考】华为OD笔试真题解析(20)--投篮大赛
数据结构·算法·华为od
环能jvav大师14 小时前
Electron桌面应用开发:创建应用
前端·javascript·windows·ui·electron·前端框架