• 数据结构之循环双链表


    LoopDLink.cpp 源码

    1. 头文件包含

    #include <stdio.h>
    #include<malloc.h>
    #include<stdlib.h>
    #include<time.h>
    typedef int ElemType;    // 元素类型
    typedef int Status;      // 返回类型
    #define OK 1             // 函数运行成功返回值
    #define ERROR 0          // 函数运行失败返回值
    
    typedef struct Node
    {
        struct Node *prior;           // 指向前一结点的指针
        ElemType date;                // 结点元素
        struct Node *next;            // 指向后一结点的指针
    }Node, *LoopDList;
    

    2. 创建循环双链表

    /*
     * 循环双链表的创建
     */
    Status CreatList(LoopDList &L, int *arr, int n)
    {
        int i;
        L = (LoopDList)malloc(sizeof(Node));         // 创建头结点
        L->next = L;
        L->prior = L;
    
        LoopDList s,p;                               // s用于开辟新结点,p指向表尾
        p = L;                                       // 指向表尾结点
    
        for(i = 0; i < n; i++)
        {
            s = (LoopDList)malloc(sizeof(Node));     // 开辟新结点
            s->date = arr[i];                        // 为新结点赋值
            p->next = s;                             // 让表尾结点的后继结点指向新结点
            s->prior = p;                            // 让新结点的前驱结点指向p
            p = s;                                   // 表尾结点指针后移
        }
        p->next = L;                                 // 使表尾结点的后继指针指向头结点
        L->prior = p;                                // 头指针的前驱结点指向表尾结点
        return OK;
    }
    

    3. 插入操作

    /*
     * 循环双向链表的插入操作
     */
    Status LoopInsert(LoopDList &L, int i, ElemType e)
    {
        int j = 1;          // 计数器,记录当前位置
        LoopDList p = L;    // 指向L,此种写法便于对当前结点的上一结点进行操作
        LoopDList s;        // 用于创建新结点
    
        while(p->next != L && j < i)
        {
            p = p->next;                // 指针后移
            j++;                        // 计数器加1
        }
        if(p->next == L || j > i)              // 判空,判位置索引不合理
            return ERROR;
        s = (LoopDList)malloc(sizeof(Node));   // 开辟新结点s
        s->date = e;             // 为s的数据域赋值
    
        s->prior = p->prior;
        s->next = p;
        p->prior->next = s;
        p->prior = s;
    
    #if 0
        p->next->prior= s;       // 使插入结点后的下一结点的前驱指向s
        s->next = p->next;       // 使s的后继结点等于p的后继结点
        s->prior= p;             // 使s的前驱结点等于p
        p->next = s;             // 使p得后继结点等于s
    #endif
        return OK;
    }
    

    4. 删除操作

    /*
     * 循环双向链表的删除操作
     * p = *L,循环体中用p->next做条件  
     * 这种写法便于对当前结点的前一结点操作,插入、删除、修改操作使用这种形式
     */
    Status DelList(LoopDList &L, int i, ElemType *e)
    {
        int j = 1;              // 记录当前位置
        LoopDList p = L;        // 指向链表
        LoopDList s;                         // 用于释放要删除的结点
        while(p->next != L && j < i)         // 判非空   判索引位置有效
        {
            p = p->next;                // 指针后移
            j++;                        // 计数器加1
        }
        if(p->next == L || j > i)        // 判空,判索引位置无效
            return ERROR;
        s = p->next;                    // 使s指向p
        *e = s->date;                   // 将要删除的结点数据赋值给e
        p->next = s->next;              // 使p的后继结点等于r的后继结点
        s->next->prior = p;             // 使s的后继的前驱结点等于p
        free(s);                        // 释放s结点
        return OK;
    }
    

    5. 查找操作

    /*
     * 循环双链表的查找
     * p = *L->next,循环体中用p做条件
     * 这种写法便于对当前结点操作,查找、遍历使用这种形式
     */
    Status GetElem(LoopDList L, int i, ElemType *e)
    {
        int j = 0;                  // 计数器
        LoopDList p = L->next;      // 指向第一个结点
        while(p != L && j < i)      // 判非空,判位置索引有效
        {
            p = p->next;            // 指针后移
            j++;                    // 计数器加1
        }
        if(p == L || j > i)         // 判空,判位置索引无效
            return ERROR;
        *e = p->date;               // 将p的数据域内容赋值给e
        return OK;
    }
    

    6. 修改操作

    /*
     * 循环双链表的修改操作
     */
    Status UpdateList(LoopDList *L, int i, ElemType e)
    {
        int j = 1;                // 记录当前位置
        LoopDList r = (*L)->next; // 指向第一个结点,此种写法便于岁当前结点操作
        while(r != *L && j < i)   // 判非空 ,判位置索引有效
        {
            r = r->next;          // 指针后移
            j++;                  // 计数器加1
        }
        if(r == *L || j > i)      // 判空,判位置索引无效
            return ERROR;
        r->date = e;              // 使r的数据域等于 e
        return OK;
    }
    

    7.正序遍历

    /*
     * 循环双链表的正序遍历
     */
    void PrintList1(LoopDList L)
    {
        LoopDList p = L->next;        // 指向L第一个结点
        if(p == L)                    // 判空
            printf("表空
    ");
        while(p != L)                 // 判非空
        {
            if(p->next != L)
                printf("[%d] -> ", p->date);
            else
                printf("[%d]",p->date);
            p = p->next;
        }
        printf("
    ");
    }
    

    8. 倒序遍历

    /*
    循环双链表的倒序遍历
    */
    void PrintList2(LoopDList L)
    {
        LoopDList p = L->prior;  // 指向L倒数第一个结点
        if(p == L)               // 判空
            printf("表空
    ");
        while(p != L)            // 判非空
        {
            if(p->prior != L)
                printf("[%d] -> ", p->date);
            else
                printf("[%d]",p->date);
            p = p->prior;
        }
        printf("
    ");
    }
    

    9. 测试函数

    int main()
    {
        LoopDList L = NULL;  // 创建链表L
        int i, e;            // i为元素位置,e为元素内容
    
        int n = 0;
        int arr[10] = {0,1,2,3,4,5,6,7,8,9};
        n = sizeof(arr)/sizeof(arr[0]);
    
    
        while(true)
        {
            printf("请选择对线性链表的操作:
    ");
            printf("1.创建
    ");
            printf("2.插入
    ");
            printf("3.删除
    ");
            printf("4.查找
    ");
            printf("5.修改
    ");
            printf("6.正序输出
    ");
            printf("7.倒序输出
    ");
            printf("8.退出
    ");
            int a;
            scanf("%d", &a);
            switch(a)
            {
                case 1:
                    if(CreatList(L, arr, n))
                        printf("创建成功
    ");
                    else
                        printf("创建失败
    ");
                    break;
                case 2:
                    printf("请输入需要插入的位置:");
                    scanf("%d", &i);
                    printf("请输入需要插入的元素:");
                    scanf("%d", &e);
                    if(LoopInsert(L, i, e))
                        printf("插入成功
    ");
                    else
                        printf("插入失败
    ");
                    break;
                case 3:
                    printf("请输入需要删除的位置:");
                    scanf("%d", &i);
                    if(DelList(L, i, &e))
                        printf("删除成功
    ");
                    else
                        printf("删除失败
    ");
                    break;
                case 4:
                    printf("请输入需要查找的位置:");
                    scanf("%d", &i);
                    GetElem(L, i, &e);
                    printf("第%d个元素为%d
    ",i,e);
                    break;
                case 5:
                    printf("请输入需要修改的位置:");
                    scanf("%d", &i);
                    printf("请输入新的的元素:");
                    scanf("%d", &e);
                    if(UpdateList(&L, i, e))
                        printf("修改成功
    ");
                    else
                        printf("修改失败
    ");
                    break;
                case 6:
                    if(L == NULL)
                    {
                        printf("表还未创建
    ");
                        break;
                    }
                    PrintList1(L);
                    break;
                case 7:
                    if(L == NULL)
                    {
                        printf("表还未创建
    ");
                        break;
                    }
                    PrintList2(L);
                    break;
                case 8:
                    return -1;
                default:
                    printf("选择错误
    ");
                    break;
            }
        }
        return 0;
    }
    

    参考
    双链表实现1: https://blog.csdn.net/weixin_43810205/article/details/88626582
    双链表实现2: https://www.cnblogs.com/likewithyou/p/5842984.html
    图解链表: https://wk.baidu.com/view/b3cc07abb04e852458fb770bf78a6529647d35cc?pcf=2
    循环单链表: https://www.cnblogs.com/yurui/p/9503164.html

    作者:yusq77

    -------------------------------------------

    Wish you all the best and good health in 2021.

  • 相关阅读:
    JavaScript—飞机大战
    JavaScript—瀑布流
    JavaScript—原生轮播和无缝滚动
    JavaScript—封装animte动画函数
    JavaScript—offset、client、scroll
    JavaScript—对象创建方式
    JavaScript—var lef const区别
    P1352 没有上司的舞会 题解
    P1829 [国家集训队]Crash的数字表格 / JZPTAB 题解
    P2522 [HAOI2011]Problem b 题解
  • 原文地址:https://www.cnblogs.com/yusq77/p/13471855.html
Copyright © 2020-2023  润新知