• 数据结构--循环链表


    目录

    1.为什么要有循环链表

    2.定义

    3.循环链表和单链表的图示对比

    4.循环链表和单链表的代码对比

    5.循环链表的操作

    1.clist.h

    2.clist.cpp

    1.初始化plist

    2.往plist中头部插入数字val

    3.往plist中的尾部插入数字val

    4.在plist中查找val值,找到返回该节点地址,失败返回NULL

    5.删除plist中的第一个val

    6.判断plist是否为空链表(没有数据节点)

    7.获取plist长度,数据节点的个数

    8.获取plist链表的pos位置的值

    9.获取val的前驱

    10.获取val的后继

    11.输出plist的所有数据


    1.为什么要有循环链表

    单链表中我们是把结点遍历一遍后就结束了,为了使表处理更加方便灵活,我们希望通过任意一个结点出发都可以找到链表中的其它结点,因此我们引入了循环链表。

    2.定义

    将单链表中终端结点的指针端由空指针改为头结点,就使整个单链表形成了一个环,这种头尾相接的单链表称为循环链表。

    简单理解就是形成一个闭合的环,在环内寻找自己需要的结点。

    3.循环链表和单链表的图示对比

    单链表:

     循环链表:

    4.循环链表和单链表的代码对比

    单链表:

    1. typedef struct Node{ //定义单链表结点类型
    2. int data; //数据域,可以是别的各种数据类型
    3. struct Node *next; //指针域
    4. }LNode, *LinkList;

    循环链表:

    1. typedef struct CNode//循环链表节点
    2. {
    3. ElemType data;//数据
    4. struct CNode* next;//后继指针
    5. }CNode ,*CList;

    5.循环链表的操作

    //带头结点的循环链表,其尾节点的后继为头结点(不是NULL)
    //节点的结构和单链表一样

    1.clist.h

    1. #pragma once
    2. typedef int ElemType;
    3. typedef struct CNode//循环链表节点
    4. {
    5. ElemType data;//数据
    6. struct CNode* next;//后继指针
    7. }CNode ,*CList;
    8. //初始化plist
    9. void InitList(CList plist);
    10. //往plist中头部插入数字val
    11. bool Insert_head(CList plist, ElemType val);
    12. //往plist中的尾部插入数字val
    13. bool Insert_tail(CList plist, ElemType val);
    14. //在plist中查找val值,找到返回该节点地址,失败返回NULL
    15. CNode* Search(CList plist, ElemType val);
    16. //删除plist中的第一个val
    17. bool DeleteVal(CList plist, ElemType val);
    18. //判断plist是否为空链表(没有数据节点)
    19. bool IsEmpty(CList plist);
    20. //获取plist长度,数据节点的个数
    21. int GetLength(CList plist);
    22. //获取plist链表的pos位置的值
    23. bool GetElem(CList plist, int pos, int* rtval);//rtval:输出参数
    24. //获取val的前驱
    25. CNode* Prior(CList plist, ElemType val);
    26. //获取val的后继
    27. CNode* Next(CList plist, ElemType val);
    28. //输出plist的所有数据
    29. void Show(CList plist);
    30. //清空数据
    31. void Clear(CList plist);
    32. //销毁
    33. void Destroy(CList plist);

    2.clist.cpp

    1.初始化plist

    1. oid InitList(CList plist)
    2. {
    3. assert(plist != NULL);
    4. if (plist == NULL)
    5. return;
    6. //数据域不使用
    7. plist->next = plist;
    8. }

    2.往plist中头部插入数字val

    这里我们需要思考一下当链表为空时是否适用:这里明确告诉大家不管是否是空链表,这两行代码均可以使用,下面给大家用示意图表示一下;
    不是空链:

     是空链:

     

    1. bool Insert_head(CList plist, ElemType val)
    2. {
    3. //1.动态申请一个新的节点
    4. CNode* p = (CNode*)malloc(sizeof(CNode));
    5. assert(p != NULL);
    6. if (p == NULL)
    7. return false;
    8. //2.把数据存放在新节点中
    9. p->data = val;
    10. //3.把新节点插入在头结点后面
    11. p->next = plist->next;
    12. plist->next = p;
    13. return true;
    14. }

    3.往plist中的尾部插入数字val

    1. bool Insert_tail(CList plist, ElemType val)
    2. {
    3. //1.创建新节点并赋值
    4. CNode* p = (CNode*)malloc(sizeof(CNode));
    5. assert(p != NULL);
    6. if (p == NULL)
    7. return false;
    8. p->data = val;
    9. //2.找到尾节点
    10. CNode* q;
    11. for (q = plist; q->next != plist; q = q->next)
    12. ;
    13. //3.插入新节点.把p插入在q的后面
    14. p->next = q->next;
    15. q->next = p;
    16. return true;
    17. }

    与单向链表的插入不同,循环单链表插入时只能往表头节点的后面插入,由初始结构可知,想完成插入操作,必须先找到要插入位置的前一个节点,然后修改相应指针即可完成操作。

     

     

    4.在plist中查找val值,找到返回该节点地址,失败返回NULL

    1. CNode* Search(CList plist, ElemType val)
    2. {
    3. for (CNode* p = plist->next; p != plist; p = p->next)
    4. {
    5. if (p->data == val)
    6. return p;
    7. }
    8. return NULL;
    9. }

    5.删除plist中的第一个val

    1. bool DeleteVal(CList plist, ElemType val)
    2. {
    3. CNode* p = Prior(plist, val);
    4. if (p == NULL)
    5. return false;
    6. CNode* q = p->next;//保存需要删除的节点
    7. p->next = q->next;//剔除q
    8. free(q);//释放节点
    9. return true;
    10. }

    6.判断plist是否为空链表(没有数据节点)

    1. bool IsEmpty(CList plist)
    2. {
    3. return plist->next == plist;
    4. }

    7.获取plist长度,数据节点的个数

    1. int GetLength(CList plist)
    2. {
    3. int count = 0;//计数器
    4. for (CNode* p = plist->next; p != plist; p = p->next)
    5. count++;
    6. return count;
    7. }

    8.获取plist链表的pos位置的值

    1. bool GetElem(CList plist, int pos, int* rtval)//rtval:输出参数
    2. {
    3. if (pos < 0 || pos >= GetLength(plist))
    4. return false;
    5. CNode* p = plist->next;
    6. for (int i = 0; i < pos; i++)
    7. {
    8. p = p->next;
    9. }
    10. *rtval = p->data;
    11. return true;
    12. }

    9.获取val的前驱

    1. CNode* Prior(CList plist, ElemType val)
    2. {
    3. for (CNode* p = plist; p->next != plist; p = p->next)
    4. {
    5. if (p->next->data == val)
    6. return p;
    7. }
    8. return NULL;
    9. }

    10.获取val的后继

    1. CNode* Next(CList plist, ElemType val)
    2. {
    3. CNode* p = Search(plist,val);
    4. if (p == NULL)
    5. return NULL;
    6. return p->next;
    7. }

    11.输出plist的所有数据

    1. void Show(CList plist)
    2. {
    3. //从头到尾遍历数据节点
    4. for (CNode* p = plist->next; p != plist; p = p->next)
    5. {
    6. printf("%d ",p->data);
    7. }
    8. printf("\n");
    9. }

    1. #include
    2. #include "clist.h"
    3. //#include //需要安装vld
    4. int main()
    5. {
    6. CNode head;//循环链表的表头节点
    7. InitList(&head);
    8. for (int i = 0; i < 10; i++)
    9. {
    10. Insert_head(&head,i);//9 8 7 6 5 4 3 2 1 0
    11. Insert_tail(&head,i);//0,1,2,3,4,5,6,7,8,9
    12. }
    13. Show(&head);
    14. CNode* p;
    15. for (int i = -1; i < 12; i++)
    16. {
    17. if ((p = Search(&head, i)) != NULL)
    18. {
    19. printf("%d找到了\n",i);
    20. }
    21. else
    22. {
    23. printf("%d没有找到\n",i);
    24. }
    25. }
    26. //for (int i = -1; i < 11; i++)
    27. //{
    28. // DeleteVal(&head,i);
    29. //}
    30. int val;
    31. GetElem(&head,3,&val);
    32. printf("%d\n",val);
    33. Show(&head);
    34. Destroy(&head);
    35. //Destroy(&head);
    36. return 0;
    37. }

     

  • 相关阅读:
    git 同时配置 gitee github
    10分钟设置免费海外远程桌面
    总结了 800多个 Kubectl 别名,再也不怕记不住命令了!
    利用IPackageManager接口进行缓存垃圾清理(释放存储)
    windows什么录屏软件好用,windows屏幕录制软件
    java+ssm基于微信小程序的高校新生自助报到迎新系统 uniapp 小程序
    r86s编译lede x86 OpenWrt
    谣言检测(SRD-PSCD)《Rumor Detection with Self-supervised Learning on Texts and Social Graph》
    nodejs的express负载均衡(续)
    【无标题】
  • 原文地址:https://blog.csdn.net/m0_59052131/article/details/128055508