• 第二章:4.线性表---循环链表和双向链表


    前言:

      循环链表:是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成了一个环。因此,从表中任意节点出发均可找到表中的其他结点。

      

      双向链表:前讨论的链式存储结构中个,每个结点都只有一个指示其后继元素的指针域,那么找下一个元素(NextElem) 的时间复杂度 为 O(1)。但是寻找直接前继元素必须要从头结点开始找,PriorElem 的时间复杂度为 O(n)。为了克服单链表的这种单向性缺点,我们在此使用一种新的链式存储结构:双向链表。

    目录:

    1.线性表的链式表示和实现

      1.1线性链表

        单链表(指针型线性链表)

        静态链表

      1.2循环链表

      1.3双向链表

    正文:

      1.2循环链表(circular linked list)

        

        循环链表的操作 和 链表的操作基本一致,差别在于循环的结束条件,链表:p->next 是否为NULL  循环链表:p->next 是否等于头指针。

        但是,很多时候在循环链表中设置 尾指针 而不是 头指针,可以简化某些操作。例如:合并两个线性表时,仅需将一个表的表尾和另一个表的表头连接即可。

                  

      1.3双向链表(double linked list)

          顾名思义,双向链表的结点中包含两个指针域,一个指向直接前驱,另一个指向直接后继。 

        在C语言中可描述如下:

          typedef  struct  DuLNode{

            ElemType   data;

            struct  DuLNode  *  prior;

            struct DuLNode   *  next;

          }DuLNode, * DuLinkList;

        双向链表也可以有循环链表:

          

        若d 为指向双向链表一个元素的指针 (即d 为 DuLinkList类型) ,则有:

          d->next->prior=d->prior->next=d;

        在双向链表中,有些操作如:ListLenght ,GetElem 和LocateElem等仅需要一个方向的指针,则他们的算法描述和 线性表的操作相同。

        但是在插入 和删除时会有很大的不同,此时要同时修改两个方向上的指针。

          

      代码实现:(双向链表的插入和删除,由于插入或删除可能需要同时修改前驱和后继的指向,因此非常容易出错)

    #include<stdio.h>
    #include<stdlib.h>

    #define TRUE 1
    #define FALSE 0
    #define OK 1
    #define ERROR 0
    #define INFEASIBLE -1
    #define OVERFLOW -2
    //链表的最大长度
    #define MAXSIZE 100

    //Status是函数的类型,其值是函数结果状态码
    typedef int Status;
    typedef int ElemType;    

    typedef  struct  DuLNode{
        ElemType   data;
        struct  DuLNode  *  prior;
        struct DuLNode   *  next;
    }DuLNode, * DuLinkList;

    //插入操作
    Status ListInsert_DuL(DuLinkList &Dul,int i,ElemType e){
        DuLNode *q=Dul;                    //q指向头结点
        int j=0;
        while(q->next&&j<(i-1)){
            q=q->next;
            j++;
        }
        
        if(!q||i<0)
            return ERROR;

        //此时 q 指向 i 的直接前驱
        DuLNode * node=(DuLinkList)malloc(sizeof(DuLNode));
        node->data=e;

        //注意:如果 i 不是追加的尾部,则需要修改 i 处元素的 前驱指针
        if(q->next){
            q->next->prior=node;    
        }
        node->next=q->next;    
        node->prior=q;
        q->next=node;

        return OK;

    }

    //删除操作
    Status ListDelete_DuL(DuLinkList &Dul,int i,ElemType &e){
        DuLNode *q=Dul;                    //q指向头结点
        int j=0;
        while(q->next&&j<i){
            q=q->next;
            j++;
        }
        if(!q||i<0)
            return ERROR;

        //执行删除操作
        q->prior->next=q->next;

        //注意:如果 i 不是追加的尾部,则需要修改 i 处元素的 前驱指针
        if(q->next)
            q->next->prior=q->prior;
        free(q);
        return OK;
    }

    //打印所有元素
    void PrintAllValues(DuLinkList &Dul){
        DuLNode *q=Dul;                    //q指向头结点
        while(q->next){
            printf("前驱:%d,",q->next->prior);
            printf("值:%d,",q->next->data);
            printf("后继:%d ",q->next->next);
            q=q->next;
        }
    }

    void main(){
        DuLNode * Dul;
        Dul=(DuLinkList)malloc(sizeof(DuLNode));
        Dul->next=NULL;
        ListInsert_DuL(Dul,1,7);
        ListInsert_DuL(Dul,1,5);
        ListInsert_DuL(Dul,1,4);
        ListInsert_DuL(Dul,1,1);
        PrintAllValues(Dul);
        
        ElemType e;
        ListDelete_DuL(Dul,3,e);
        printf("%s ","删除第3个元素");
        PrintAllValues(Dul);
    }

      运行结果:

        1、错误实例:

        错误原因:虽然成功的删除了双向链表的 第 3 个元素,但是 忘记修改第 4 个元素的 前驱指针。

        

        2.正确为:

        

  • 相关阅读:
    图数据库查询语言
    深入探索Spring Data JPA, 从Repository 到 Specifications 和 Querydsl
    axios 浏览器内存泄露问题解决
    给Swagger换一套皮肤 Knife4j集成记录
    根据经纬度和半径计算经纬度范围
    最火 Web 前端组态软件 (可视化)
    Python-----删除给定目录下的所有文件
    Python----发送邮件yagmail
    python------将"["1","2"]"类型是字符串,转换为["1","2"]类型为列表,即eval()用法
    python----自动生成requirements.txt与导入requirements.txt中的库
  • 原文地址:https://www.cnblogs.com/ahguSH/p/6184893.html
Copyright © 2020-2023  润新知