📜  数据结构-队列的链表实现(1)

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

数据结构-队列的链表实现

队列是一种基本的数据结构,它具有先进先出(FIFO)的特点。在队列中,元素只会在队列的一端(称为队尾)添加,而在另一端(称为队头)删除。队列的链表实现是一种常见的实现方式。

队列的基本操作

队列的基本操作包括入队和出队两个操作:

  • 入队:将元素添加到队尾。
  • 出队:从队头删除元素并返回该元素。

此外,队列还有两个基本属性:

  • 队列长度:队列中当前存储的元素个数。
  • 队列空间:队列的存储空间大小。当队列中的元素个数达到队列空间时,队列就满了。
链表实现队列

队列的链表实现是一种基于链表的实现方式,它的数据结构类似于链表。每个节点包含两个指针,一个指向该节点的数据,一个指向下一个节点。头节点指向队头,尾节点指向队尾。

定义数据结构

为了实现队列的链表实现,我们需要定义节点和队列两个数据结构。我们可以使用结构体来定义这两个数据结构。

/**
 * 队列节点结构体
 */
typedef struct QueueNode {
    void *data;  // 指向节点数据的指针
    struct QueueNode *next;  // 指向下一个节点的指针
} QueueNode;

/**
 * 队列结构体
 */
typedef struct Queue {
    QueueNode *head;  // 指向队头节点的指针
    QueueNode *tail;  // 指向队尾节点的指针
    int size;  // 队列中元素的数量
    int capacity;  // 队列的最大容量
} Queue;
初始化队列

在使用队列之前,我们需要先初始化队列。初始化队列时,我们需要为队列分配内存,并将队列的头和尾都初始化为 NULL

/**
 * 初始化队列
 * @param queue 队列指针
 * @param capacity 队列的最大容量
 */
void queue_init(Queue *queue, int capacity) {
    queue->head = NULL;
    queue->tail = NULL;
    queue->size = 0;
    queue->capacity = capacity;
}
入队操作

队列的入队操作是向队列的尾部添加一个元素。为了实现入队操作,我们需要先创建一个新的节点,并将该节点的 data 指针指向要添加的元素。然后,我们将新的节点添加到队列的尾部,并更新队列的 size 属性。

/**
 * 入队操作
 * @param queue 队列指针
 * @param data 要入队的数据
 * @return 返回操作结果。如果入队成功,返回 0;否则返回 -1。
 */
int queue_enqueue(Queue *queue, void *data) {
    // 如果队列已满,返回错误
    if (queue->size == queue->capacity) {
        return -1;
    }
    // 创建新节点
    QueueNode *node = (QueueNode *) malloc(sizeof(QueueNode));
    node->data = data;
    node->next = NULL;
    // 如果队列为空,将头尾指向新节点
    if (queue->size == 0) {
        queue->head = node;
        queue->tail = node;
    } else {
        // 将新节点添加到队列尾部,更新队列尾指针
        queue->tail->next = node;
        queue->tail = node;
    }
    // 更新队列元素数量
    queue->size++;
    return 0;
}
出队操作

队列的出队操作是从队列的头部删除一个元素。为了实现出队操作,我们需要先获取队列头部的元素,然后将队列头部的节点删除,并将该节点的 data 指针返回。

/**
 * 出队操作
 * @param queue 队列指针
 * @return 返回队列头部的数据。如果队列为空,返回 NULL。
 */
void *queue_dequeue(Queue *queue) {
    // 如果队列为空,返回 NULL
    if (queue->size == 0) {
        return NULL;
    }
    // 获取队列头部节点的数据
    QueueNode *node = queue->head;
    void *data = node->data;
    // 更新队列头指针,并释放节点内存
    queue->head = node->next;
    free(node);
    // 更新队列元素数量
    queue->size--;
    return data;
}
查询队列状态

我们可以通过以下函数查询队列的状态:

/**
 * 查询队列元素数量
 * @param queue 队列指针
 * @return 返回队列中元素的数量
 */
int queue_size(Queue *queue) {
    return queue->size;
}

/**
 * 查询队列容量
 * @param queue 队列指针
 * @return 返回队列的容量
 */
int queue_capacity(Queue *queue) {
    return queue->capacity;
}

/**
 * 查询队列是否为空
 * @param queue 队列指针
 * @return 如果队列为空,返回 1;否则返回 0。
 */
int queue_is_empty(Queue *queue) {
    return queue->size == 0;
}

/**
 * 查询队列是否已满
 * @param queue 队列指针
 * @return 如果队列已满,返回 1;否则返回 0。
 */
int queue_is_full(Queue *queue) {
    return queue->size == queue->capacity;
}
总结

队列的链表实现是一种基于链表的实现方式,它的数据结构类似于链表。每个节点包含两个指针,一个指向该节点的数据,一个指向下一个节点。头节点指向队头,尾节点指向队尾。队列的基本操作包括入队和出队两个操作,此外,队列还有两个基本属性:队列长度和队列空间。队列的链表实现可以在不限制队列长度的情况下使用。