📜  循环队列 |第 2 组(循环链表实现)(1)

📅  最后修改于: 2023-12-03 15:25:37.711000             🧑  作者: Mango

循环队列 |第 2 组(循环链表实现)

简介

循环队列是一种基于数组实现的队列,与普通队列不同的是,在队列为空时,队头指针与队尾指针相等;在队列满时,队尾指针回到数组起始位置(0),队头指针则继续向后移动。这种队列可以通过模运算实现。

本文介绍的是循环队列的第 2 组实现方式,即基于循环链表的实现。循环链表是一种特殊的链表,在普通链表的基础上,将最后一个节点指向了头节点,从而形成了环形结构。

实现过程
定义队列结构体

首先,我们需要定义一个结构体,表示循环队列。该结构体包含两个指向节点的指针,分别指向队头和队尾,以及一个队列的长度。

typedef struct {
    QueueNode *front;   // 队头指针
    QueueNode *rear;    // 队尾指针
    int length;         // 队列长度
} CircularQueue;
定义节点结构体

接下来,我们需要定义一个节点结构体,表示链表中的一个节点。该节点包含两个属性:一个整数值(表示实际存储的数据)和一个指向下一个节点的指针。

typedef struct QueueNode {
    int data;               // 数据
    struct QueueNode *next; // 指向下一个节点的指针
} QueueNode;
初始化循环队列

在使用循环队列之前,需要先对其进行初始化。初始化过程需要创建一个头节点,并将队头和队尾指针指向该节点。

void init(CircularQueue *queue) {
    QueueNode *head = (QueueNode *) malloc(sizeof(QueueNode));  // 创建头节点
    head->next = head;              // 将头节点的next指针指向自己,形成环形结构
    queue->front = queue->rear = head;   // 初始化队头和队尾指针为头节点
    queue->length = 0;              // 队列长度置为0
}
入队操作

入队操作需要新建一个节点,并将其插入到队尾节点的后面即可。

void enqueue(CircularQueue *queue, int x) {
    QueueNode *new_node = (QueueNode *) malloc(sizeof(QueueNode));   // 创建新节点
    new_node->data = x;     // 为新节点赋值
    new_node->next = queue->rear->next;   // 将新节点的next指针指向头节点
    queue->rear->next = new_node;     // 将新节点插入到队尾节点的后面
    queue->rear = new_node;     // 将队尾指针指向新节点
    queue->length++;            // 队列长度+1
}
出队操作

出队操作需要删除队头节点,并将队头指针指向下一个节点。

int dequeue(CircularQueue *queue) {
    if (queue->front == queue->rear) {  // 队列为空,无法出队
        return -1;
    }
    QueueNode *del_node = queue->front->next;   // 获取队头节点
    int value = del_node->data;            // 保存队头节点的data值
    queue->front->next = del_node->next;   // 将队头节点的下一个节点作为新的队头节点
    if (queue->rear == del_node) {     // 如果被删节点是队列中的唯一节点,更新队尾指针
        queue->rear = queue->front;
    }
    free(del_node);      // 释放被删除节点的内存
    queue->length--;        // 队列长度-1
    return value;
}
获取队头元素

获取队头元素的操作比较简单,直接返回队头节点的下一个节点的data值即可。

int getFront(CircularQueue *queue) {
    if (queue->front == queue->rear) {  // 队列为空,无法获取队头元素
        return -1;
    }
    return queue->front->next->data;    // 获取队头节点的下一个节点的data值
}
获取队列长度

获取队列长度也比较简单,直接返回队列结构体中的长度属性即可。

int getLength(CircularQueue *queue) {
    return queue->length;
}
总结

循环队列是一种高效的数据结构,常用于实现缓冲池、任务队列等场景。该文章介绍了循环队列的第 2 组实现方式,即基于循环链表的实现。相比于数组实现,循环链表实现更加灵活和高效,因此在一些场合下更为适用。