循环链表是一种数据结构,其中最后一个节点的next连接回到第一个节点,形成一个循环。此结构允许连续遍历而不会中断。
循环链表对于日程安排和音乐播放列表等任务特别有用,这允许播放完毕后回到第一首继续播放。
在这小节中,我们将介绍循环链表的基础知识、如何使用它们、它们的优点和缺点以及它们的应用。

什么是循环链表?

循环链表是一种特殊类型的链表,其中所有节点都连接起来形成一个
与我们前面讲到的链表不同的是,循环链表中的最后一个节点的next指向第一个节点。这意味着当遍历到尾部时可以继续向头部遍历。

循环链表是从单链表双链表扩展出来的,因此,循环链表基本只有这两种类型。

循环单链表

在循环单链表中,每个节点只有一个指针,称为next指针。 最后一个节点的next指针指向第一个节点,这样就形成了一个环。在循环单链表中,我们只能沿一个方向遍历链表。

循环单链表结构

循环单链表结构

数据结构

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

#include <stdio.h>

#include <stdlib.h>

#define ElemType int

typedef struct LNode {

int data;

struct LNode* next;

} LNode, *LinkList;

LNode* pTemp = (LNode*)malloc(sizeof(LNode));

pTemp->data = e;

pTemp->next = p->next; // 将新节点的next指向p的下一个节点

p->next = pTemp; // 更新p的next指向新节点,完成插入操

// 完整代码:https://totuma.cn
  • data:数据域,也是节点的值
  • next:指针域,指向下一个结点的指针

在上面的定义中,每个节点都有data数据域next指针域,和普通的单链表结构一模一样,唯一区别就是当我们为循环链表创建多个节点时,我们只需要将最后一个节点连接回第一个节点即可。

循环单链表的基本操作实现

创建循环单链表

插入是链表中的基本操作。和普通单链表的唯一区别是将最后一个节点的next连接到第头结点。
插入大概可以分为以下三种情况

1.在空链表中插入新结点

在空链表中插入新结点

在空链表中插入新结点

这里使用的是带头结点的单链表来实现循环链表,所以链表空的条件是头结点的next指向头结点,即头结点自己指向自己。
在空的循环链表中插入一个节点,需要创建一个新结点,将其next指针指向头结点,以达到循环的目的。

2.在链表中部插入新结点

在链表中部插入新结点

在链表中部插入新结点

和普通单链表操作一样,在中部插入结点并没有改变尾结点next的指向。

3.在链表尾部插入新结点

在链表尾部插入新结点

在链表尾部插入新结点

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

#include <stdio.h>

#include <stdlib.h>

#define ElemType int

typedef struct LNode {

int data;

struct LNode* next;

} LNode, *LinkList;

LNode* pTemp = (LNode*)malloc(sizeof(LNode));

pTemp->data = e;

pTemp->next = p->next; // 将新节点的next指向p的下一个节点

p->next = pTemp; // 更新p的next指向新节点,完成插入操

// 完整代码:https://totuma.cn

上面三种情况,都可以统一为同一操作:

  • 1.找到待插入位置的前驱结点,即p

  • 2.创建新结点pTemp

  • 3.使pTempnext指向pnext

    (如果是空链表,那么p的next指向头结点本身。如果是在末尾插入,p的next同样也是指向头结点)

  • 4.使pnext指向pTemp

按位序插入结点 | 可视化完整可视化

2.4 循环单链表详解 - 线性表教程 使用动画可视化你的代码

图码-数据结构可视化动画版

什么是循环链表?

循环 链表 是所有节点连接成一个圆的链表。 在循环链表中,第一个节点和最后一个节点相互连接,形成一个循环。 末尾没有NULL。

循环链表 

循环链表一般有两种类型:

  • 循环单链表: 在循环单链表中,链表的最后一个节点包含指向链表第一个节点的指针。 我们遍历循环单链表,直到到达起始节点。 循环单链表没有起点也没有终点。 任何节点的下一部分中都不存在空值。

循环单链表的表示

  • 循环双向链表: 循环双向链表兼有双向链表和循环链表的性质,其中两个连续的元素通过前一个和后一个指针链接或连接,最后一个节点通过下一个指针指向第一个节点,并且第一个节点通过前一个指针指向最后一个节点。

循环双向链表的表示

注意: 我们将使用单循环链表来表示循环链表的工作方式。

循环链表的表示:

循环链表与单链表类似,只是将最后一个节点连接到第一个节点。

循环链表的节点表示:

C

struct Node {
    int data;
    struct Node *next;
};


            

C++

Python3

Java

C#

Javascript

PHP

循环单链表示例:

上面的循环单链表可以表示为:

C

Node* one = createNode(3);
Node* two = createNode(5);
Node* three = createNode(9);
  
// Connect nodes
one->next = two;
two->next = three;
three->next = one;


            

C++

Python3

Java

C#

Javascript

PHP

解释: 在上面的程序中,一、二、三分别是值为 3、5、9 的节点,它们以循环方式连接:

  • 对于节点一: Next 指针存储节点二的地址。
  • 对于节点二: 下一个存储节点三的地址
  • 对于节点三: Next 指向节点一。

循环链表的操作:

我们可以对循环链表进行一些类似于单链表的操作,分别是:

  1. 插入
  2. 删除

1、 循环链表中的插入:

可以通过三种方式添加节点:

  1. 在列表开头插入
  2. 在列表末尾插入
  3. 在节点之间插入

1) 在链表开头插入: 要在链表开头插入节点,请按以下步骤操作: 

  • 创建一个节点,比如 T。 
  • 使 T -> 下一个 = 最后一个 -> 下一个。 
  • 最后一个 -> 下一个 = T。 

插入前的循环链表

进而, 

插入后的循环链表

2) 在链表末尾插入: 要在链表末尾插入节点,请执行以下步骤: 

  • 创建一个节点,比如 T。 
  • 使 T -> 下一个 = 最后一个 -> 下一个; 
  • 最后一个 -> 下一个 = T。 
  • 最后=T。 

插入前,

末尾插入节点之前的循环链表

插入后,

末尾插入节点后的循环链表

3) 在节点之间插入: 要在两个节点之间插入节点,请按照下列步骤操作: 

  • 创建一个节点,比如 T。 
  • 查找需要插入T的节点,假设该节点为P。 
  • 使 T -> 下一个 = P -> 下一个; 
  • P -> 下一个 = T。

假设节点值为10后需要插入12,

插入前的循环链表

经过查找和插入后,

插入后的循环链表

2、循环链表中的删除:

1) 仅当该节点是循环链表中唯一的节点时才删除该节点:

  • 释放节点的内存
  • 最后一个值应该为 NULL 一个节点总是指向另一个节点,因此不需要 NULL 赋值。
    可以将任意节点设置为起点。
    从第一个节点到最后一个节点快速遍历。

2)删除最后一个节点:

  • 找到最后一个节点之前的节点(让它是临时的)
  • 保留 temp 中最后一个节点旁边的节点的地址
  • 删除最后的记忆
  • 把温度放在最后

3)从循环链表中删除任意节点: 我们将得到一个节点,我们的任务是从循环链表中删除该节点。

算法:
情况 1 :列表为空。 

  • 如果列表为空,我们将简单地返回。

情况 2 :列表不为空  

  • 如果列表不为空,那么我们定义两个指针 curr prev 并用 节点初始化指针 curr
  • 使用curr 遍历链表 找到要删除的节点,在移动到 curr 到下一个节点之前,每次设置 prev = curr。
  • 如果找到该节点,请检查它是否是列表中的唯一节点。 如果是,则设置 head = NULL 和 free(curr)。
  • 如果列表有多个节点,请检查它是否是列表的第一个节点。 检查这个的条件(curr == head)。 如果是,则移动 prev 直到到达最后一个节点。 当 prev 到达最后一个节点后,设置 head = head -> next 和 prev -> next = head。 删除当前。
  • 如果 curr 不是第一个节点,我们检查它是否是列表中的最后一个节点。 检查的条件是(curr -> next == head)。
  • 如果 curr 是最后一个节点。 设置 prev -> next = head 并通过 free(curr) 删除节点 curr。
  • 如果要删除的节点既不是第一个节点,也不是最后一个节点,则设置prev -> next = curr -> next,删除curr。
  • 如果该节点不存在于列表中,则返回头并且不执行任何操作。

下面是上述方法的实现:

C

#include <stdio.h>
#include <stdlib.h>
  
// Structure for a node
struct Node {
    int data;
    struct Node* next;
};
  
// Function to insert a node at the
// beginning of a Circular linked list
void push(struct Node** head_ref, int data)
{
  
    // Create a new node and make head
    // as next of it.
    struct Node* ptr1 = (struct Node*)malloc(sizeof(struct Node));
    ptr1->data = data;
    ptr1->next = *head_ref;
  
    // If linked list is not NULL then
    // set the next of last node
    if (*head_ref != NULL) {
  
        // Find the node before head and
        // update next of it.
        struct Node* temp = *head_ref;
        while (temp->next != *head_ref)
            temp = temp->next;
        temp->next = ptr1;
    }
    else
  
        // For the first node
        ptr1->next = ptr1;
  
    *head_ref = ptr1;
}
  
// Function to print nodes in a given
// circular linked list
void printList(struct Node* head)
{
    struct Node* temp = head;
    if (head != NULL) {
        do {
            printf("%d ", temp->data);
            temp = temp->next;
        } while (temp != head);
    }
  
    printf("\n");
}
  
// Function to delete a given node
// from the list
void deleteNode(struct Node** head, int key)
{
  
    // If linked list is empty
    if (*head == NULL)
        return;
  
    // If the list contains only a
    // single node
    if ((*head)->data == key && (*head)->next == *head) {
        free(*head);
        *head = NULL;
        return;
    }
  
    struct Node *last = *head, *d;
  
    // If head is to be deleted
    if ((*head)->data == key) {
  
        // Find the last node of the list
        while (last->next != *head)
            last = last->next;
  
        // Point last node to the next of
        // head i.e. the second node
        // of the list
        last->next = (*head)->next;
        free(*head);
        *head = last->next;
        return;
    }
  
    // Either the node to be deleted is
    // not found or the end of list
    // is not reached
    while (last->next != *head && last->next->data != key) {
        last = last->next;
    }
  
    // If node to be deleted was found
    if (last->next->data == key) {
        d = last->next;
        last->next = d->next;
        free(d);
    }
    else
        printf("Given node is not found in the list!!!\n");
}
  
// Driver code
int main()
{
    // Initialize lists as empty
    struct Node* head = NULL;
  
    // Created linked list will be
    // 2->5->7->8->10
    push(&head, 2);
    push(&head, 5);
    push(&head, 7);
    push(&head, 8);
    push(&head, 10);
  
    printf("List Before Deletion: ");
    printList(head);
  
    deleteNode(&head, 7);
  
    printf("List After Deletion: ");
    printList(head);
  
    return 0;
}


            

C++

Java

Python3

Javascript

C#

输出

删除前列表:10 8 7 5 2
删除后列表:10 8 5 2

时间复杂度: O(N),最坏的情况发生在要删除的元素是最后一个元素并且我们需要遍历整个列表时。
辅助空间: O(1),使用恒定的额外空间。

循环链表的优点:  

  • 任何节点都可以作为起点。 我们可以从任意点开始遍历整个列表。 我们只需要在再次访问第一个访问的节点时停止即可。 
  • 对于队列的实现很有用。 与此 实现不同的是 ,如果我们使用循环链表,则不需要维护 front 和 back 两个指针。 我们可以维护一个指向最后插入的节点的指针,并且前面总是可以作为最后一个的下一个获得。
 
  • 循环列表在重复遍历列表的应用程序中非常有用。 例如,当PC上运行多个应用程序时,操作系统通常会将正在运行的应用程序放在一个列表中,然后循环遍历它们,给每个应用程序一段时间来执行,然后让它们等待一段时间。 CPU 被分配给另一个应用程序。 操作系统使用循环列表是很方便的,这样当它到达列表末尾时,它可以循环到列表的前面。 
  • 循环双向链表用于实现 斐波那契堆 等高级数据结构。
  •  与其他更复杂的数据结构(如树或图)相比,实现循环链​​表相对容易。

循环链表的缺点:

  • 与单链表相比,循环表更为复杂。
  • 反转循环列表比单次或双重反转循环列表更复杂。
  • 如果处理不仔细,代码有可能进入无限循环。
  • 找到列表末尾并控制循环更加困难。
  • 尽管循环链表在某些应用程序中可能很高效,但在某些情况下(例如需要对列表进行排序或搜索时),它们的性能可能比其他数据结构慢。
  • 循环链表不提供对单个节点的直接访问

循环链表的应用:

  • 多人游戏利用这一点为每个玩家提供玩游戏的机会。
  • 循环链表可用于组织操作系统上多个正在运行的应用程序。 这些应用程序由操作系统迭代。
  • 循环链表可以用于资源分配问题。
  • 循环链表通常用于实现循环缓冲区,
  • 循环链表可用于模拟和游戏。

为什么要循环链表?

  • 一个节点总是指向另一个节点,因此不需要 NULL 赋值。
  • 可以将任意节点设置为起点。
  • 从第一个节点到最后一个节点快速遍历。

下一篇文章: 循环链表 | 集合 2(遍历) 循环单链表 | 插入 如果您在上述代码/算法中发现任何错误,请写评论,或寻找其他方法来解决相同的问题

无论你的目标是考试成功、职业发展,还是纯粹的兴趣,这个数据结构和算法可视化的网站都会是一个无价的资源。

前往这个网站,开始你的学习之旅吧!

这些是常见的:【C语言描述】《数据结构和算法》数据结构JAVA实现 数据结构与算法基础(青岛大学-王卓)数据结构与算法王道数据结构c语言实现 速成数据结构期末考前救急 数据结构视频C语言版教程 数据结构严蔚敏 数据结构郝斌 数据结构考研 JAVA数据结构算法与基础 数据结构王道 2022数据结构学习 数据结构小甲鱼 王卓 学习数据结构 数据结构浙江大学 数据结构复习 数据结构马士兵 数据结构零基础教程 数据结构和算法 数据结构入门 考研数据结构习题讲解 数据结构期末复习 计算机二级

为什么要使用头插法创建,而不是尾插法创建?

如果我们要在链表末尾进行插入,那么需要先遍历整个链表找到尾结点,或者使用一个变量记录尾结点的。
而且每次都需要改变尾结点的next指向头结点,以达到循环。
而我们使用头插法,无论链表是否为空,代码都是统一不变,不需要做其他判断。

按位序删除结点

删除操作和普通单链表相同。主要区别在于我们需要确保删除后链表保持循环。

要从循环链表中删除特定的结点,首先需要检查删除的位序是否满足条件。
找到待删除结点的前驱结点即p结点
找到前驱结点p后,使用q记录为待删除结点
修改前驱结点p的next指向待删除结点q的next,即跳过q结点并将其删除

仅有一个结点时,循环指向头结点

仅有一个结点时,循环指向头结点

仅有一个结点时,循环指向头结点

删除尾部结点,更新链表循环

删除尾部结点,更新链表循环

删除尾部结点,更新链表循环

删除中间结点

删除中间结点

删除中间结点

💡 提示

对于带头结点的链表,上面三种情况都可以统一为同一种操作代码

按位序删除结点 | 可视化完整可视化

2.4 循环单链表详解 - 线性表教程 使用动画可视化你的代码

图码-数据结构可视化动画版

什么是循环链表?

循环 链表 是所有节点连接成一个圆的链表。 在循环链表中,第一个节点和最后一个节点相互连接,形成一个循环。 末尾没有NULL。

循环链表 

循环链表一般有两种类型:

  • 循环单链表: 在循环单链表中,链表的最后一个节点包含指向链表第一个节点的指针。 我们遍历循环单链表,直到到达起始节点。 循环单链表没有起点也没有终点。 任何节点的下一部分中都不存在空值。

循环单链表的表示

  • 循环双向链表: 循环双向链表兼有双向链表和循环链表的性质,其中两个连续的元素通过前一个和后一个指针链接或连接,最后一个节点通过下一个指针指向第一个节点,并且第一个节点通过前一个指针指向最后一个节点。

循环双向链表的表示

注意: 我们将使用单循环链表来表示循环链表的工作方式。

循环链表的表示:

循环链表与单链表类似,只是将最后一个节点连接到第一个节点。

循环链表的节点表示:

C

struct Node {
    int data;
    struct Node *next;
};


            

C++

Python3

Java

C#

Javascript

PHP

循环单链表示例:

上面的循环单链表可以表示为:

C

Node* one = createNode(3);
Node* two = createNode(5);
Node* three = createNode(9);
  
// Connect nodes
one->next = two;
two->next = three;
three->next = one;


            

C++

Python3

Java

C#

Javascript

PHP

解释: 在上面的程序中,一、二、三分别是值为 3、5、9 的节点,它们以循环方式连接:

  • 对于节点一: Next 指针存储节点二的地址。
  • 对于节点二: 下一个存储节点三的地址
  • 对于节点三: Next 指向节点一。

循环链表的操作:

我们可以对循环链表进行一些类似于单链表的操作,分别是:

  1. 插入
  2. 删除

1、 循环链表中的插入:

可以通过三种方式添加节点:

  1. 在列表开头插入
  2. 在列表末尾插入
  3. 在节点之间插入

1) 在链表开头插入: 要在链表开头插入节点,请按以下步骤操作: 

  • 创建一个节点,比如 T。 
  • 使 T -> 下一个 = 最后一个 -> 下一个。 
  • 最后一个 -> 下一个 = T。 

插入前的循环链表

进而, 

插入后的循环链表

2) 在链表末尾插入: 要在链表末尾插入节点,请执行以下步骤: 

  • 创建一个节点,比如 T。 
  • 使 T -> 下一个 = 最后一个 -> 下一个; 
  • 最后一个 -> 下一个 = T。 
  • 最后=T。 

插入前,

末尾插入节点之前的循环链表

插入后,

末尾插入节点后的循环链表

3) 在节点之间插入: 要在两个节点之间插入节点,请按照下列步骤操作: 

  • 创建一个节点,比如 T。 
  • 查找需要插入T的节点,假设该节点为P。 
  • 使 T -> 下一个 = P -> 下一个; 
  • P -> 下一个 = T。

假设节点值为10后需要插入12,

插入前的循环链表

经过查找和插入后,

插入后的循环链表

2、循环链表中的删除:

1) 仅当该节点是循环链表中唯一的节点时才删除该节点:

  • 释放节点的内存
  • 最后一个值应该为 NULL 一个节点总是指向另一个节点,因此不需要 NULL 赋值。
    可以将任意节点设置为起点。
    从第一个节点到最后一个节点快速遍历。

2)删除最后一个节点:

  • 找到最后一个节点之前的节点(让它是临时的)
  • 保留 temp 中最后一个节点旁边的节点的地址
  • 删除最后的记忆
  • 把温度放在最后

3)从循环链表中删除任意节点: 我们将得到一个节点,我们的任务是从循环链表中删除该节点。

算法:
情况 1 :列表为空。 

  • 如果列表为空,我们将简单地返回。

情况 2 :列表不为空  

  • 如果列表不为空,那么我们定义两个指针 curr prev 并用 节点初始化指针 curr
  • 使用curr 遍历链表 找到要删除的节点,在移动到 curr 到下一个节点之前,每次设置 prev = curr。
  • 如果找到该节点,请检查它是否是列表中的唯一节点。 如果是,则设置 head = NULL 和 free(curr)。
  • 如果列表有多个节点,请检查它是否是列表的第一个节点。 检查这个的条件(curr == head)。 如果是,则移动 prev 直到到达最后一个节点。 当 prev 到达最后一个节点后,设置 head = head -> next 和 prev -> next = head。 删除当前。
  • 如果 curr 不是第一个节点,我们检查它是否是列表中的最后一个节点。 检查的条件是(curr -> next == head)。
  • 如果 curr 是最后一个节点。 设置 prev -> next = head 并通过 free(curr) 删除节点 curr。
  • 如果要删除的节点既不是第一个节点,也不是最后一个节点,则设置prev -> next = curr -> next,删除curr。
  • 如果该节点不存在于列表中,则返回头并且不执行任何操作。

下面是上述方法的实现:

C

#include <stdio.h>
#include <stdlib.h>
  
// Structure for a node
struct Node {
    int data;
    struct Node* next;
};
  
// Function to insert a node at the
// beginning of a Circular linked list
void push(struct Node** head_ref, int data)
{
  
    // Create a new node and make head
    // as next of it.
    struct Node* ptr1 = (struct Node*)malloc(sizeof(struct Node));
    ptr1->data = data;
    ptr1->next = *head_ref;
  
    // If linked list is not NULL then
    // set the next of last node
    if (*head_ref != NULL) {
  
        // Find the node before head and
        // update next of it.
        struct Node* temp = *head_ref;
        while (temp->next != *head_ref)
            temp = temp->next;
        temp->next = ptr1;
    }
    else
  
        // For the first node
        ptr1->next = ptr1;
  
    *head_ref = ptr1;
}
  
// Function to print nodes in a given
// circular linked list
void printList(struct Node* head)
{
    struct Node* temp = head;
    if (head != NULL) {
        do {
            printf("%d ", temp->data);
            temp = temp->next;
        } while (temp != head);
    }
  
    printf("\n");
}
  
// Function to delete a given node
// from the list
void deleteNode(struct Node** head, int key)
{
  
    // If linked list is empty
    if (*head == NULL)
        return;
  
    // If the list contains only a
    // single node
    if ((*head)->data == key && (*head)->next == *head) {
        free(*head);
        *head = NULL;
        return;
    }
  
    struct Node *last = *head, *d;
  
    // If head is to be deleted
    if ((*head)->data == key) {
  
        // Find the last node of the list
        while (last->next != *head)
            last = last->next;
  
        // Point last node to the next of
        // head i.e. the second node
        // of the list
        last->next = (*head)->next;
        free(*head);
        *head = last->next;
        return;
    }
  
    // Either the node to be deleted is
    // not found or the end of list
    // is not reached
    while (last->next != *head && last->next->data != key) {
        last = last->next;
    }
  
    // If node to be deleted was found
    if (last->next->data == key) {
        d = last->next;
        last->next = d->next;
        free(d);
    }
    else
        printf("Given node is not found in the list!!!\n");
}
  
// Driver code
int main()
{
    // Initialize lists as empty
    struct Node* head = NULL;
  
    // Created linked list will be
    // 2->5->7->8->10
    push(&head, 2);
    push(&head, 5);
    push(&head, 7);
    push(&head, 8);
    push(&head, 10);
  
    printf("List Before Deletion: ");
    printList(head);
  
    deleteNode(&head, 7);
  
    printf("List After Deletion: ");
    printList(head);
  
    return 0;
}


            

C++

Java

Python3

Javascript

C#

输出

删除前列表:10 8 7 5 2
删除后列表:10 8 5 2

时间复杂度: O(N),最坏的情况发生在要删除的元素是最后一个元素并且我们需要遍历整个列表时。
辅助空间: O(1),使用恒定的额外空间。

循环链表的优点:  

  • 任何节点都可以作为起点。 我们可以从任意点开始遍历整个列表。 我们只需要在再次访问第一个访问的节点时停止即可。 
  • 对于队列的实现很有用。 与此 实现不同的是 ,如果我们使用循环链表,则不需要维护 front 和 back 两个指针。 我们可以维护一个指向最后插入的节点的指针,并且前面总是可以作为最后一个的下一个获得。
 
  • 循环列表在重复遍历列表的应用程序中非常有用。 例如,当PC上运行多个应用程序时,操作系统通常会将正在运行的应用程序放在一个列表中,然后循环遍历它们,给每个应用程序一段时间来执行,然后让它们等待一段时间。 CPU 被分配给另一个应用程序。 操作系统使用循环列表是很方便的,这样当它到达列表末尾时,它可以循环到列表的前面。 
  • 循环双向链表用于实现 斐波那契堆 等高级数据结构。
  •  与其他更复杂的数据结构(如树或图)相比,实现循环链​​表相对容易。

循环链表的缺点:

  • 与单链表相比,循环表更为复杂。
  • 反转循环列表比单次或双重反转循环列表更复杂。
  • 如果处理不仔细,代码有可能进入无限循环。
  • 找到列表末尾并控制循环更加困难。
  • 尽管循环链表在某些应用程序中可能很高效,但在某些情况下(例如需要对列表进行排序或搜索时),它们的性能可能比其他数据结构慢。
  • 循环链表不提供对单个节点的直接访问

循环链表的应用:

  • 多人游戏利用这一点为每个玩家提供玩游戏的机会。
  • 循环链表可用于组织操作系统上多个正在运行的应用程序。 这些应用程序由操作系统迭代。
  • 循环链表可以用于资源分配问题。
  • 循环链表通常用于实现循环缓冲区,
  • 循环链表可用于模拟和游戏。

为什么要循环链表?

  • 一个节点总是指向另一个节点,因此不需要 NULL 赋值。
  • 可以将任意节点设置为起点。
  • 从第一个节点到最后一个节点快速遍历。

下一篇文章: 循环链表 | 集合 2(遍历) 循环单链表 | 插入 如果您在上述代码/算法中发现任何错误,请写评论,或寻找其他方法来解决相同的问题

无论你的目标是考试成功、职业发展,还是纯粹的兴趣,这个数据结构和算法可视化的网站都会是一个无价的资源。

前往这个网站,开始你的学习之旅吧!

这些是常见的:【C语言描述】《数据结构和算法》数据结构JAVA实现 数据结构与算法基础(青岛大学-王卓)数据结构与算法王道数据结构c语言实现 速成数据结构期末考前救急 数据结构视频C语言版教程 数据结构严蔚敏 数据结构郝斌 数据结构考研 JAVA数据结构算法与基础 数据结构王道 2022数据结构学习 数据结构小甲鱼 王卓 学习数据结构 数据结构浙江大学 数据结构复习 数据结构马士兵 数据结构零基础教程 数据结构和算法 数据结构入门 考研数据结构习题讲解 数据结构期末复习 计算机二级