当前位置: 首页 > news >正文

数据结构——队列(Queue)

数据结构——队列(Queue)

一、队列的基本概念

  1. 定义
    队列(Queue)是一种先进先出(First In First Out,FIFO)的线性数据结构。

  2. 特点
    • 只允许在**队尾(rear)插入,在队头(front)**删除。
    • 插入称为 入队(Enqueue),删除称为 出队(Dequeue)

二、队列的抽象数据类型(ADT)描述

ADT Queue {Data: 线性序列Operations:enqueue(x)   // 入队dequeue()    // 出队并返回队首peek()       // 查看队首isEmpty()    // 判空size()       // 返回元素个数
}

    三、队列的常见应用场景(如任务调度、消息队列、BFS算法等)

    • 操作系统:进程/线程就绪队列、打印任务队列
    • 网络:TCP 报文重组、消息队列(Kafka、RabbitMQ)
    • 算法:BFS 层序遍历、滑动窗口最大值、缓存 LRU
    • 前端:JS 事件循环宏任务/微任务队列

    四、队列的实现方式

    1. 基于数组的静态队列
      思路:用一段连续内存存储,维护 frontrear 两个索引。
      问题:出队后前面空间浪费 → 采用循环队列

    2. 基于链表的动态队列
      思路:用带头指针 front 和尾指针 rear 的单链表,无需考虑容量。

    3. 循环队列(Circular Queue)
      • 逻辑上把数组视为环,模运算取余。
      • 牺牲一个空位或维护计数器区分空/满。
      • 优势:O(1) 入队/出队,空间利用率高。

    五、队列的基本操作复杂度

    操作  数组队列(循环)链表队列说明  
    Enqueue O(1)O(1)尾插
    DequeueO(1)O(1)头删
    PeekO(1)O(1)直接读 front
    SizeO(1) 或 O(n)O(1)若维护计数器
    SpaceO(n)O(n)均与元素数成正比

    六、队列的变种与扩展

    1. 双端队列(Deque)
      两端都可插入删除,可用于滑动窗口最大值撤销/重做

    2. 优先队列(Priority Queue)
      按优先级出队:二叉堆 O(log n),斐波那契堆 O(1) amortized。

    3. 阻塞队列(Blocking Queue)
      线程安全,满/空时阻塞等待,用于生产者-消费者。

    4. 并发队列(Concurrent Queue)
      无锁 CAS 实现(如 Java ConcurrentLinkedQueue),高并发场景。

    七、完整代码实现

    #define  _CRT_SECURE_NO_WARNINGS 
    #include<stdio.h>
    #include<stdlib.h>
    #define Maxsize 5
    typedef int ElemType;
    //队列的顺序存储结构和基本运算实现
    typedef struct
    {ElemType data[Maxsize];int front, rear;
    }SqQueue;// 1)初始化队列
    void InitQueue(SqQueue & q)
    {q.front = q.rear = -1;
    }//2) 判断队列是否为空
    bool QueueEmpty(SqQueue* q)
    {return (q->front == q->rear);
    }
    // 3)进队列
    bool enQueue(SqQueue& q, ElemType e)
    {if (q.rear == Maxsize - 1)//队满上溢出return false;q.rear++;q.data[q.rear] = e;return true;
    }
    // 4)出队列 
    bool deQueue(SqQueue& q, ElemType& e)
    {if (q.front == q.rear)//队空下溢出return false;q.front++;e = q.data[q.front];return true;
    }
    bool PrintQueue(SqQueue q)
    {if (q.front == q.rear)//队空下溢出return false;int i = 0;while (i <= q.rear){printf("%d->", q.data[i++]);}printf("end\n");return true;
    }int main()
    {SqQueue	Q1;InitQueue(Q1);int x = 0;scanf("%d", &x);int i = Q1.rear;while (x != 9999 && Q1.rear <Maxsize - 1){enQueue(Q1, x);scanf("%d", &x);}PrintQueue(Q1);return 0;}//为了解决假溢出,引进循环队列 //循环队列会牺牲一个存储单元// 1)初始化队列
    void InitQueue1(SqQueue*& q)
    {q = (SqQueue*)malloc(sizeof(SqQueue));q->front = q->rear = -1;
    }
    // 2) 销毁队列
    void DestroyQueue1(SqQueue*& q)
    {free(q);
    }
    //3) 判断队列是否为空
    bool QueueEmpty1(SqQueue* q)
    {return (q->front == q->rear);
    }
    // 4)进队列
    bool enQueue1(SqQueue*& q, ElemType e)
    {if ((q->rear+1)%Maxsize==q->front)//队满上溢出return false;q->rear=(q->rear+1)%Maxsize;q->data[q->rear] = e;return true;
    }
    // 5)出队列 
    bool deQueue1(SqQueue*& q, ElemType& e)
    {if (q->front == q->rear)//队空下溢出return false;q->front = (q->front+1)%Maxsize;e = q->data[q->front]; return true;
    }
    //6)判断队满
    /*队列的链式存储结构及其基本运算的实现*/typedef struct qnode 
    {ElemType data;struct qnode* next;//下一个结点指针
    }DataNode;  //链队数据结点的类型
    typedef struct 
    {DataNode* front;//指向队头结点DataNode* rear;//指向队尾结点
    }LinkQuNode;   //链队结点的类型  // 1) 初始化队列
    void InitLinkQueue(LinkQuNode*& q)
    {q = (LinkQuNode*)malloc(sizeof(LinkQuNode));q->front = q->rear = NULL;
    }
    void DestroyLinkQueue(LinkQuNode*& q)
    {DataNode* pre = q->front, * p;if (pre != NULL){p = pre->next;while (p != NULL){free(pre);pre = p;p = p->next;}free(pre);}free(q);
    }
    // 3)判断是否为空bool LinkQueueEempty(LinkQuNode* q)
    {return (q->rear == NULL);
    }// 4)进队列
    bool  enLinkQueue(LinkQuNode*& q, ElemType e)
    {DataNode* p = (DataNode*)malloc(sizeof(DataNode));p->data = e;p->next = NULL;if (q->rear == q->front) {//如果链队为空,不带头节点的第一个元素入队需要特殊处理q->rear = p;q->front = p;}else{q->rear->next = p;q->rear = p;}return true;
    }
    //5)出队列
    bool deLinkQueue(LinkQuNode*& q, ElemType& e)
    {if (q->rear==NULL)//链队为空return false;DataNode* p=q->front;e = p->data;q->front = p->next;  //移动if (q->rear == p)//当出队时,链队只有一个结点需要移动队尾指针q->front = q->rear = NULL;free(p);return true;
    }

    常见面试题与解答

    Q1. 如何用两个栈实现队列?
    答:入队压入栈 A,出队时若栈 B 空则把 A 全部倒入 B,B 弹出即 FIFO。均摊 O(1)。

    Q2. 循环队列如何判断空/满?
    答:① 牺牲一个单元 (rear+1)%cap==front 为满;② 额外计数器 size==capacity。

    Q3. 队列与栈的区别?
    答:队列 FIFO,栈 LIFO;栈可 DFS,队列可 BFS;两者可互相模拟(两栈/两队列)。

    Q4. 线程安全的队列实现?
    答:Java ArrayBlockingQueue, ConcurrentLinkedQueue; C++ std::queue + 互斥锁;无锁环形缓冲区(Disruptor)。

    http://www.dtcms.com/a/315376.html

    相关文章:

  • Linux学习—数据结构(链表2)
  • 红队信息收集工具oneforall子域名搜集爆破工具安装使用教程详细过程
  • 句子表征-文本匹配--representation-based/interactive-based
  • 【华为机试】685. 冗余连接 II
  • 补:《每日AI-人工智能-编程日报》--2025年7月28日
  • 【深度学习新浪潮】近三年零样本图像分类研发进展调研
  • mongodb 和 mysql 相关操作
  • 【C++】语法基础篇
  • 厄米系统(Hermitian System)
  • 【大模型05】Embedding和向量数据库
  • 【测试】⾃动化测试概念篇
  • 用户与组管理命令
  • python算法【楼梯数量计算】
  • Hadoop HDFS 3.3.4 讲解~
  • linux的用户操作(详细介绍)
  • 牛客笔试题错题整理(1)
  • Field and wave electromagnetics 复习
  • 【编程实践】点云曲率计算与可视化
  • Pimpl惯用法
  • 【秋招笔试】2025.08.03虾皮秋招笔试-第二题
  • [GYCTF2020]FlaskApp
  • 0804 进程
  • 【笔记】重学单片机(51)(下)
  • 数据结构——并查集及C++实现
  • Javascript面试题及详细答案150道(046-060)
  • 5天从0到1!用阿里Qwen3-Coder开发故障调度指挥室系统,运维也能搞定开发
  • 嵌入式 C 语言入门:函数指针基础笔记 —— 从计算器优化到指针本质
  • 文本转语音(TTS)脚本
  • 【项目实践】在系统接入天气api,根据当前天气提醒,做好plan
  • C语言的控制语句