>> >> >> Reference << << << <<<<<<Ref>>>>>>
>> >> >> Indexer << << << <<<<<<Idx>>>>>>
Matched: 0

Tags

    Categories

      Types

        Top Results

          Queue
          M: 2025-12-31 - ljf12825

          Queue(队列)

          基本特性

          • FIFO原则:最先添加的元素最先被移除
          • 两个主要操作端
            • 队尾(rear/back):添加元素的位置
            • 队头(front/head):移除元素的位置
          • 约束:只能在两端操作,不能在中间插入或删除

          逻辑结构

          ┌─────────────────────────────────────────┐
          │                 Queue                   │
          ├──────────┬──────┬──────┬──────┬─────────┤
          │   Front  │      │      │      │   Rear  │
          │  (Head)  │      │      │      │  (Tail) │
          ├──────────┴──────┴──────┴──────┴─────────┤
          │   ^ 出队方向               入队方向 ^   │
          │   <──────────────────────────────────── │
          └─────────────────────────────────────────┘
          

          状态演变

          初始状态(空队列):
          ┌───┬───┬───┬───┬───┬───┐
          │   │   │   │   │   │   │
          └───┴───┴───┴───┴───┴───┘
          ^
          front = rear = 0
          
          入队元素 A:
          ┌───┬───┬───┬───┬───┬───┐
          │ A │   │   │   │   │   │
          └───┴───┴───┴───┴───┴───┘
          ↑      ^
          front  rear
          
          入队元素 B, C:
          ┌───┬───┬───┬───┬───┬───┐
          │ A │ B │ C │   │   │   │
          └───┴───┴───┴───┴───┴───┘
          ^            ^
          front        rear
          
          出队元素 A:
          ┌───┬───┬───┬───┬───┬───┐
          │   │ B │ C │   │   │   │
          └───┴───┴───┴───┴───┴───┘
               ^       ^
              front   rear
          

          操作

          • 入队(enqueue)
            • 在队尾添加元素,时间复杂度O(1)
          • 出队(dequeue)
            • 从队头移除并返回元素,时间复杂度O(1)
          • 查看队头元素,不移除(peek)
            • 时间复杂度:O(1)
          • 检查队列是否为空
          • 返回队列中元素数量

          实现

          基本队列(Naive Queue)

          基于数组的实现

          这是一种很直观的做法,但是非常不推荐\

          实现方式

          • 用数组arr[N]存储元素
          • front指向队头,rear指向队尾
          • 入队:arr[rear++] = x
          • 出队:返回arr[front++]

          操作很简单,但是会造成以下问题

          • 空间浪费
            • 出队操作后,front会不断右移
            • 数组前面的空间空了,但无法复用
            • 例如:容量10,入队10个,出队5个,数组前半部分空了,但rear还在10 -> 后续最多只能再放0个元素
          • 低效的解决方式
            • 可以每次出队后,把数组前半部分的元素整体向左移动
            • 代价高:O(n)每次出队 -> 很慢

          这种做法仅适用于理解队列状态变化
          工业级基于数组的实现是Circular Queue

          基于链表的实现

          这是正统的做法

          特点

          • enqueue:O(1)
          • dequeue:O(1)
          • 不需要扩容
          head -> [A] -> [B] -> [C] -> null
          

          双端队列(Deque)

          Deque(Double Ended Queue),可以在队头和队尾进行插入和删除操作的数据结构

          操作含义时间复杂度
          push_front从头部插入O(1)
          push_back从尾部插入O(1)
          pop_front从头部删除O(1)
          pop_back从尾部删除O(1)

          逻辑结构

          ┌─────────────────────────────────────────┐
          │               Deque                     │
          ├───────┬─────────┬─────────┬─────────────┤
          │ Front │         │         │     Rear    │
          │ (Head)│         │         │    (Tail)   │
          ├───────┴─────────┴─────────┴─────────────┤
          │  ← 出/入队方向        出/入队方向 →     │
          └─────────────────────────────────────────┘
          

          状态演变

          初始状态:
          ┌───┬───┬───┬───┬───┐
          │   │   │   │   │   │
          └───┴───┴───┴───┴───┘
          
          从前端添加 X,从后端添加 Y:
          ┌───┬───┬───┬───┬───┐
          │ X │   │   │   │ Y │
          └───┴───┴───┴───┴───┘
           ↑               ↑
          front          rear
          
          继续从前端添加 A,从后端添加 B:
          ┌───┬───┬───┬───┬───┐
          │ A │ X │   │ Y │ B │
          └───┴───┴───┴───┴───┘
           ↑           ↑
          front      rear
          

          实现

          双向链表实现
          结构
          node <-> node <-> node
          
          优点
          • 实现简单
          • 任意长度
          • 插入删除绝对O(1)
          缺点
          • 每个节点两个指针 -> 内存大
          • cache miss 非常严重
          • 实际性能差

          高性能场景不会使用这个版本

          循环数组

          这是最常见的手写实现

          核心思想

          用一个数组 + 两个索引

          [ _ _ A B C D _ _ ]
                ↑       ↑
              head    tail
          

          索引取模

          next = (i + 1) % capacity;
          
          结构
          buffer[]
          head index
          tail index
          size
          
          优点
          • 连续内存
          • cache 极友好
          • 实现简单
          • 实际工程最常用
          缺点
          • 需要扩容
          • 扩容需要整体搬移
          STL风格分段数组

          这是std::deque的真实实现方式

          结构类似这样

          [block][block][block][block]
             ↓      ↓
           [64]   [64]
          

          本质是指针数组 -> 每个指针指向一个小块连续内存

          优点
          • 两端扩容不用整体搬迁
          • 连续块 + 灵活
          • 综合性能最强
          缺点
          • 实现复杂
          • 手写成本高

          使用场景

          Deque的接口简单,底层实现高度工程化
          适合用于两端高频操作的场景
          Deque是系统级最重要的数据结构之一
          简单程度像队列,工程价值像内存管理器
          算法领域Deque是万金油

          不该使用Deque的场景

          • 只尾部push/pop -> vector
          • 只FIFO -> queue
          • 需要随机访问 -> vector
          • 任意位置插删 -> list
          • 按优先级 -> priority_queue

          一旦开始用Deque的中间索引访问元素,说明选错结构了

          优先队列(Priority Queue)

          循环队列(Circular Queue)

          阻塞队列(Blocking Queue)

          应用场景

          1. BFS
          2. 生产者/消费者模型
          3. 任务调度/消息系统
          4. 单调队列