十念 发表于 2024-12-14 23:34:58

2.10.循环链表

https://i-blog.csdnimg.cn/direct/89539fb2e9dd435fb3c4c68f5fa6783b.png
一.循环单链表:

1.图示:

https://i-blog.csdnimg.cn/direct/04452b0229354305ba7c1a9653b8edb3.png
2.代码阐明:

https://i-blog.csdnimg.cn/direct/398c675206f0409ba55dbe9ed69a426c.png


[*] 初始化循环单链表时头结点的next指针必须指向头结点
[*] 判断循环单链表是否为空只需要判断头结点的next指针是否指向头结点?是:循环单链表为空;否:循环单链表不为空
[*] 判断某个结点是否为循环单链表的表尾结点,只需要判断该结点的next指针是否指向该循环单链表的头结点即可
[*] 如果循环单链表不为空的话,就需要把表尾结点的next指针指向头结点
3.代码演示:

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

typedef struct LNode
{
    int data; //这个数据的类型不是固定的
    struct LNode *next;
}LNode,*LinkList;

//初始化一个循环单链表
bool InitList(LinkList &L) //函数的结果和函数体的结果最终都要用,所以加&
{
    L = (LNode *)malloc( sizeof(LNode) ); //分配一个头结点
    if(L==NULL)
    {
      return false; //内存不足,分配失败
    }
    L->next = L; //头结点的next指针必须指向L即头结点指向头结点(L代表头结点)
    return true;
}

//判断循环单链表是否为空
bool Empty(LinkList L)
{
    if(L->next = L) return true; //头结点指向头结点说明为空
    else return false;
}

//判断结点p是否为循环单链表的表尾结点
bool isTail(LinkList L,LNode *p)
{
    //L代表头结点
    if(p->next = L) //p结点的next指针指回头结点就说明p为表尾结点
    {
      return true;
    }
    else
    {
      return false;
    }
}

int main()
{
    return 0;
} 4.循环单链表与非循环单链表的对比:

https://i-blog.csdnimg.cn/direct/2c6c6e9cc4a04c39ac7534185790d93a.png
5.基础操作:

https://i-blog.csdnimg.cn/direct/034ee9a1e4764f3ca84b3044eaea65be.png
循环单链表和非循环单链表找到尾结点的时间复杂度都是O(n),因为要重新循环遍历到尾;
循环单链表从尾部找到头部的时间复杂度为O(1),因为尾部下一个就是头部->如果经常操作表头和表尾的话,可以让循环单链表的指针指向表尾结点,此时如果在表尾插入或删除结点时大概需要修改该指针;
二.循环双链表:

1.图示:

https://i-blog.csdnimg.cn/direct/6d0e12c588a94a828019ba8fc8ded7e0.png
2.代码阐明:

https://i-blog.csdnimg.cn/direct/5f797ce0ce90420dbb219c40ec5a24dc.png
3.代码演示:

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

typedef struct DNode
{
    int data;
    struct DNode *prior,*next; //*prior为前驱指针,*next为后继指针
}DNode,*DLinklist;


//初始化空的循环单链表
bool InitDLinkList(DLinklist &L)
{
    L = (DNode *)malloc( sizeof(DNode) ); //分配一个头结点
    if(L==NULL) return false; //内存不足,分配失败
    L->prior = L; //头结点的前驱指针prior指向头结点
    L->next = L; //头结点的后继指针next指向头结点
    return true;
}

//判断循环双链表是否为空
bool Empty(DLinklist L)
{
    if(L->next = L)
    {
      return true; //循环双链表的头结点的next指针指向头结点就说明循环双链表为空
    }
    else
    {
      return false;
    }
}

//判断结点p是否为循环双链表的表尾结点
bool isTail(DLinklist L,DNode *p)
{
    if(p->next == L) //结点p的next指针指向头结点就说明p为尾结点
    {
      return true;
    }
    else
    {
      return false;
    }
}


int main()
{
    return 0;
} 4.循环双链表的插入:

https://i-blog.csdnimg.cn/direct/e57db6b13f2444b0ace597390b0cb52e.png
5.循环双链表的删除:

https://i-blog.csdnimg.cn/direct/08aabbdf0fa14a64a719b236001a19d4.png
三.总结:

https://i-blog.csdnimg.cn/direct/b0cf5bb5ce2f4985b14b55cc82234407.png
1.对于平凡带头结点的双链表而言,只有头结点时,它的后继指针和前驱指针都指向NULL;
2.知道表为空时的状态就可以知道怎样初始化;
3.知道怎样判断某个结点是否是表头/尾结点时,就可以知道怎样前向遍历和后向遍历;
4.注:所有链表都不具有随机访问的特性,因此找某个结点时只能通过循环查找,循环要么停在表头结点,要么停在表尾结点。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 2.10.循环链表