数据结构-队列

一、了解队列

队列的定义

队列是一种先进先出(FIFO, First In First Out)的数据结构。它的基本特性是:在队列中,元素的插入(入队)发生在队尾,元素的删除(出队)发生在队头。队列通常用于需要按顺序处理数据的场景。

基本操作

  1. 初始化队列 :创建一个空队列。InitQueue(SqQueue* Q)

  2. 入队 :将元素添加到队尾。bool EnQueue(SqQueue* Q, int e)

  3. 出队 :从队头移除元素并返回该元素。bool DeQueue(SqQueue* Q, int* e)

  4. 获取队头元素 :查看队头元素但不移除它。bool GetHead(SqQueue Q, int* e)

  5. 检查队列是否为空 :判断队列是否包含元素。bool isEmpty(SqQueue Q)

  6. 获取队列长度 :返回队列中当前元素的数量。int LengthQueue(SqQueue Q)

队列的作用

  1. 任务调度:在操作系统中,队列用于管理任务的执行顺序。
  2. 数据缓冲:在生产者-消费者模型中,队列用于存储生产者生成的数据,以便消费者按顺序处理。
  3. 广度优先搜索(BFS):在图论算法中,队列用于实现广度优先搜索。
  4. 网络请求处理:在服务器中,队列用于管理请求的处理顺序。

队列的优缺点

优点
  1. 简单易用:队列的逻辑结构简单,易于理解和实现。
  2. 高效的插入和删除:在队列的两端(队头和队尾)进行插入和删除操作的时间复杂度为 O(1)。
  3. 适用场景广泛:队列在许多算法和应用中具有重要作用,如任务调度、数据流处理等。
缺点
  1. 固定大小:使用数组实现的队列在初始化时需要定义最大容量,可能导致空间浪费或溢出。
  2. 内存管理:使用链表实现的队列需要额外的内存管理,可能导致内存碎片。
  3. 访问限制:只能访问队头和队尾的元素,无法随机访问队列中的其他元素。

二、队列的顺序存储结构(C语言)

1. 顺序存储结构

#define MaxSize 50 // 定义队列的最大容量为50

// 定义顺序队列的结构体
typedef struct {
    int data[MaxSize]; // 存储队列元素的数组
    int front;         // 队列头指针,指向队列的第一个元素
    int rear;          // 队列尾指针,指向队列的最后一个元素的下一个位置
} SqQueue;

2. 初始化队列

// 初始化队列
void InitQueue(SqQueue* Q) {
    Q->front = 0; // 将队列头指针初始化为0
    Q->rear = 0;  // 将队列尾指针初始化为0
}

3. 入队

// 入队操作
bool EnQueue(SqQueue* Q, int e) {
    // 判断队列是否已满,使用环形队列的特性
    if ((Q->rear + 1) % MaxSize == Q->front) return false;
    Q->data[Q->rear] = e; // 将元素e插入到队列尾
    Q->rear = (Q->rear + 1) % MaxSize; // 更新尾指针
    return true; // 返回成功
}

4. 出队

// 出队操作
bool DeQueue(SqQueue* Q, int* e) {
    // 判断队列是否为空
    if (Q->front == Q->rear) return false;
    *e = Q->data[Q->front]; // 将队列头元素赋值给e
    Q->front = (Q->front + 1) % MaxSize; // 更新头指针
    return true; // 返回成功
}

5. 获取队头元素

// 获取队列头元素
bool GetHead(SqQueue Q, int* e) {
    // 判断队列是否为空
    if (Q.front == Q.rear) return false;
    *e = Q.data[Q.front]; // 将队列头元素赋值给e
    return true; // 返回成功
}

6. 检查队列是否为空

// 判断队列是否为空
bool isEmpty(SqQueue Q) {
    return Q.front == Q.rear; // 如果头指针和尾指针相等,则队列为空
}

7. 获取队列长度

// 获取队列的长度
int LengthQueue(SqQueue Q) {
    // 计算队列当前长度
    return (Q.rear + MaxSize - Q.front) % MaxSize;
}

三、队列的链式存储结构(C语言)

1. 链式存储结构

// 定义链表节点
typedef struct QNode {
    int data;              // 存储数据
    struct QNode* next;   // 指向下一个节点的指针
} QNode;

// 定义链式队列
typedef struct {
    QNode* front;         // 队列头指针
    QNode* rear;          // 队列尾指针
    int length;           // 队列长度
} LinkQueue;

2. 初始化队列

// 初始化队列
bool InitQueue(LinkQueue* Q) {
    Q->front = (QNode*)malloc(sizeof(QNode)); // 创建一个空节点
    if (Q->front == NULL) {
        Q->rear = NULL;
        return false; // 检查内存分配
    }

    Q->front->next = NULL; // 空节点的下一个指针指向NULL
    Q->rear = Q->front; // front 和 rear 指向同一个空节点
    Q->length = 0; // 初始化长度为0
    return true;
}

3. 入队

// 入队操作
bool EnQueue(LinkQueue* Q, int e) {
    QNode* p = (QNode*)malloc(sizeof(QNode)); // 创建新节点
    if (p == NULL) return false; // 检查内存分配
    p->data = e; // 设置节点数据
    p->next = NULL; // 新节点的下一个指针指向NULL

    Q->rear->next = p; // 将新节点链接到队列尾
    Q->rear = p; // 更新队列尾指针

    if (Q->length == 0) {
        Q->front = p; // 如果队列之前为空,更新队列头指针
    }

    Q->length++; // 更新队列长度
    return true; // 返回成功
}

4. 出队

// 出队操作
bool DeQueue(LinkQueue* Q, int* e) {
    // 判断队列是否为空
    if (Q->length == 0) return false;
    *e = Q->front->data; // 获取队头元素
    QNode* p = Q->front; // 保存当前头节点
    Q->front = p->next; // 更新队头指针
    free(p); // 释放原头节点
    Q->length--; // 更新队列长度
    return true; // 返回成功
}

5. 获取队头元素

// 获取队列头元素
bool GetHead(LinkQueue Q, int* e) {
    // 判断队列是否为空
    if (Q.length == 0) return false;
    *e = Q.front->data; // 获取队头元素
    return true; // 返回成功
}

6. 检查队列是否为空

// 判断队列是否为空
bool isEmpty(LinkQueue Q) {
    return Q.length == 0; // 如果长度为0,则队列为空
}

7. 获取队列长度

// 获取队列的长度
int LengthQueue(LinkQueue Q) {
    return Q.length; // 返回队列长度
}

四、总代码(C语言)

1. 顺序存储结构-使用示例

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

#define MaxSize 50 // 定义队列的最大容量为50

// 定义顺序队列的结构体
typedef struct {
    int data[MaxSize]; // 存储队列元素的数组
    int front;         // 队列头指针,指向队列的第一个元素
    int rear;          // 队列尾指针,指向队列的最后一个元素的下一个位置
} SqQueue;

// 初始化队列
void InitQueue(SqQueue* Q) {
    Q->front = 0; // 将队列头指针初始化为0
    Q->rear = 0;  // 将队列尾指针初始化为0
}

// 判断队列是否为空
bool isEmpty(SqQueue Q) {
    return Q.front == Q.rear; // 如果头指针和尾指针相等,则队列为空
}

// 入队操作
bool EnQueue(SqQueue* Q, int e) {
    // 判断队列是否已满,使用环形队列的特性
    if ((Q->rear + 1) % MaxSize == Q->front) return false;
    Q->data[Q->rear] = e; // 将元素e插入到队列尾
    Q->rear = (Q->rear + 1) % MaxSize; // 更新尾指针
    return true; // 返回成功
}

// 出队操作
bool DeQueue(SqQueue* Q, int* e) {
    // 判断队列是否为空
    if (Q->front == Q->rear) return false;
    *e = Q->data[Q->front]; // 将队列头元素赋值给e
    Q->front = (Q->front + 1) % MaxSize; // 更新头指针
    return true; // 返回成功
}

// 获取队列的长度
int LengthQueue(SqQueue Q) {
    // 计算队列当前长度
    return (Q.rear + MaxSize - Q.front) % MaxSize;
}

// 获取队列头元素
bool GetHead(SqQueue Q, int* e) {
    // 判断队列是否为空
    if (Q.front == Q.rear) return false;
    *e = Q.data[Q.front]; // 将队列头元素赋值给e
    return true; // 返回成功
}



int main() {
    SqQueue Q;
    InitQueue(&Q); // 初始化队列

    // 入队操作
    for (int i = 1; i <= 5; i++) {
        if (EnQueue(&Q, i)) {
            printf("入队: %d\n", i);
        }
        else {
            printf("队列已满,无法入队: %d\n", i);
        }
    }

    // 获取队头元素
    int head;
    if (GetHead(Q, &head)) {
        printf("队头元素: %d\n", head);
    }
    else {
        printf("队列为空,无法获取队头元素。\n");
    }

    // 输出队列长度
    printf("当前队列长度: %d\n", LengthQueue(Q));

    // 出队操作
    int e;
    while (!isEmpty(Q)) {
        if (DeQueue(&Q, &e)) {
            printf("出队: %d\n", e);
        }
        else {
            printf("队列为空,无法出队。\n");
        }
    }

    // 再次检查队列是否为空
    if (isEmpty(Q)) {
        printf("队列现在为空。\n");
    }

    return 0;
}

2. 链式存储结构

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

// 定义链表节点
typedef struct QNode {
    int data;              // 存储数据
    struct QNode* next;   // 指向下一个节点的指针
} QNode;

// 定义链式队列
typedef struct {
    QNode* front;         // 队列头指针
    QNode* rear;          // 队列尾指针
    int length;           // 队列长度
} LinkQueue;

// 初始化队列
bool InitQueue(LinkQueue* Q) {
    Q->front = (QNode*)malloc(sizeof(QNode)); // 创建一个空节点
    if (Q->front == NULL) {
        Q->rear = NULL;
        return false; // 检查内存分配
    }

    Q->front->next = NULL; // 空节点的下一个指针指向NULL
    Q->rear = Q->front; // front 和 rear 指向同一个空节点
    Q->length = 0; // 初始化长度为0
    return true;
}

// 判断队列是否为空
bool isEmpty(LinkQueue Q) {
    return Q.length == 0; // 如果长度为0,则队列为空
}

// 入队操作
bool EnQueue(LinkQueue* Q, int e) {
    QNode* p = (QNode*)malloc(sizeof(QNode)); // 创建新节点
    if (p == NULL) return false; // 检查内存分配
    p->data = e; // 设置节点数据
    p->next = NULL; // 新节点的下一个指针指向NULL

    Q->rear->next = p; // 将新节点链接到队列尾
    Q->rear = p; // 更新队列尾指针

    if (Q->length == 0) {
        Q->front = p; // 如果队列之前为空,更新队列头指针
    }

    Q->length++; // 更新队列长度
    return true; // 返回成功
}

// 出队操作
bool DeQueue(LinkQueue* Q, int* e) {
    // 判断队列是否为空
    if (Q->length == 0) return false;
    *e = Q->front->data; // 获取队头元素
    QNode* p = Q->front; // 保存当前头节点
    Q->front = p->next; // 更新队头指针
    free(p); // 释放原头节点
    Q->length--; // 更新队列长度
    return true; // 返回成功
}

// 获取队列的长度
int LengthQueue(LinkQueue Q) {
    return Q.length; // 返回队列长度
}

// 获取队列头元素
bool GetHead(LinkQueue Q, int* e) {
    // 判断队列是否为空
    if (Q.length == 0) return false;
    *e = Q.front->data; // 获取队头元素
    return true; // 返回成功
}

int main() {
    LinkQueue Q;
    int e;

    // 初始化队列  
    if (!InitQueue(&Q)) {
        printf("初始化队列失败\n");
        return 1; // 初始化失败,退出程序  
    }

    // 检查队列是否为空  
    if (isEmpty(Q)) {
        printf("队列为空\n");
    }

    // 入队操作  
    EnQueue(&Q, 10);
    EnQueue(&Q, 20);
    EnQueue(&Q, 30);

    // 获取队列长度  
    printf("队列长度: %d\n", LengthQueue(Q));

    // 获取队列头元素  
    if (GetHead(Q, &e)) {
        printf("队列头元素: %d\n", e);
    }

    // 出队操作并打印  
    while (!isEmpty(Q)) {
        if (DeQueue(&Q, &e)) {
            printf("出队元素: %d\n", e);
        }
    }

    // 再次检查队列是否为空  
    if (isEmpty(Q)) {
        printf("队列为空\n");
    }

    // 清理工作
    // 释放所有节点
    QNode* current = Q.front;
    while (current != NULL) {
        QNode* temp = current;
        current = current->next;
        free(temp);
    }

    return 0;
}

参考:

  1. 数据结构-栈

  2. 数据结构-线性表-了解循环链表

  3. 数据结构-线性表-单链表

相关推荐
搬砖的小码农_Sky21 分钟前
C语言:数组
c语言·数据结构
先鱼鲨生2 小时前
数据结构——栈、队列
数据结构
一念之坤2 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年2 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王2 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
liujjjiyun3 小时前
小R的随机播放顺序
数据结构·c++·算法
Reese_Cool5 小时前
【数据结构与算法】排序
java·c语言·开发语言·数据结构·c++·算法·排序算法
djk88885 小时前
.net将List<实体1>的数据转到List<实体2>
数据结构·list·.net
搬砖的小码农_Sky6 小时前
C语言:结构体
c语言·数据结构
_OLi_7 小时前
力扣 LeetCode 106. 从中序与后序遍历序列构造二叉树(Day9:二叉树)
数据结构·算法·leetcode