数据结构 - 队列

220 阅读3分钟

在阅读本文前, 请先阅读以下一篇文章.

数据结构 - 单链表 - 掘金 (juejin.cn)

一. 队列的定义

队列是一种特殊的线性表, 其只允许在一端(队尾)进行插入数据操作, 在另一端(队首)进行删除数据操作,队列中的数据元素遵循先进先出 FIFO (First In First Out) 的原则.

image.png

二. 队列各种接口的实现

此处的队列采用单链表的结构实现, 因为如果使用顺序表的结构, 出队列时在顺序表头上出数据,效率相对较低.

image.png

typedef int QDataType;

typedef struct QueueNode
{
    QDataType data;    // 数据域
    struct QueueNode* next;    // 指针域
}QNode;

typedef struct Queue
{
    QNode* head;    // 队首
    QNode* tail;    // 队尾
    int size;    // 队列有效数据个数
}Queue;

1. 初始化

创建好结构体后, 对其进行初始化.

void QueueInit(Queue* pq)
{
    assert(pq);

    pq->head = pq->tail = NULL;
    pq->size = 0;
}

2. 销毁

当不再使用队列时, 将链表从队首到队尾逐个节点销毁.

void QueueDestroy(Queue* pq)
{
    assert(pq);
    QNode* curr = pq->head;
    while (curr) {
        QNode* temp = curr->next;
        free(curr);
        curr = temp;
    }

    pq->head = pq->tail = NULL;
    pq->size = 0;
}

3. 队尾入队列

入队, 即将数据元素从队尾插入队列中.

image.png

void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);   

    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL) {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;

    if (pq->head == NULL) {
        assert(pq->tail == NULL);
        pq->head = pq->tail = newnode;
    } else {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }

    pq->size++;
}

4. 队首出队列

出队, 即将数据元素从队首弹出.

image.png

void QueuePop(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    if (pq->head->next == NULL) {
        free(pq->head);
        pq->head = pq->tail = NULL;
    } else {
        QNode* temp = pq->head->next;
        free(pq->head);
        pq->head = temp;
    }

    pq->size--;
}

5. 返回队列中有效数据个数

返回队列中有效元素个数.

int QueueSize(Queue* pq)
{
    assert(pq);

    return pq->size;
}

6. 检测队列是否为空

检测队列是否为空.

bool QueueEmpty(Queue* pq)
{
    assert(pq);

    return pq->size == 0;
}

7. 获取队首元素

获取队首元素.

QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->head->data; 
}

8. 获取队尾元素

获取队尾元素.

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->tail->data; 
}

三. 队列的源码

Queue.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int QDataType;

typedef struct QueueNode
{
    QDataType data;    // 数据域
    struct QueueNode* next;    // 指针域
}QNode;

typedef struct Queue
{
    QNode* head;    // 队首
    QNode* tail;    // 队尾
    int size;    // 队列有效数据个数
}Queue;

// 初始化
void QueueInit(Queue* pq);

// 销毁
void QueueDestroy(Queue* pq);

// 队尾入队列
void QueuePush(Queue* pq, QDataType x);

// 队首出队列
void QueuePop(Queue* pq);

// 返回队列中有效数据个数
int QueueSize(Queue* pq);

// 检测队列是否为空
bool QueueEmpty(Queue* pq);

// 获取队首元素
QDataType QueueFront(Queue* pq);

// 获取队尾元素
QDataType QueueBack(Queue* pq);

Queue.c

#include "Queue.h"

void QueueInit(Queue* pq)
{
    assert(pq);

    pq->head = pq->tail = NULL;
    pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
    assert(pq);
    QNode* curr = pq->head;
    while (curr) {
        QNode* temp = curr->next;
        free(curr);
        curr = temp;
    }

    pq->head = pq->tail = NULL;
    pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
    assert(pq);   

    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL) {
        perror("malloc fail");
        return;
    }
    newnode->data = x;
    newnode->next = NULL;

    if (pq->head == NULL) {
        assert(pq->tail == NULL);
        pq->head = pq->tail = newnode;
    } else {
        pq->tail->next = newnode;
        pq->tail = newnode;
    }

    pq->size++;
}

void QueuePop(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    if (pq->head->next == NULL) {
        free(pq->head);
        pq->head = pq->tail = NULL;
    } else {
        QNode* temp = pq->head->next;
        free(pq->head);
        pq->head = temp;
    }

    pq->size--;
}

int QueueSize(Queue* pq)
{
    assert(pq);

    return pq->size;
}

bool QueueEmpty(Queue* pq)
{
    assert(pq);

    return pq->size == 0;
}

QDataType QueueFront(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->head->data; 
}

QDataType QueueBack(Queue* pq)
{
    assert(pq);
    assert(!QueueEmpty(pq));

    return pq->tail->data; 
}