数据结构——4. 队列

一、 队列的基本概念

1. 什么是队列?
队列 (Queue) 是一种特殊的线性表,其操作受到限制:所有插入操作只能在表的一端进行,而所有删除操作则在另一端进行。

  • 队尾 (Rear): 允许插入的一端。
  • 队头 (Front): 允许删除的一端。
  • 入队 (Enqueue): 插入新元素到队尾的操作。
  • 出队 (Dequeue): 从队头删除元素的操作。

2. 核心特性:先进先出 (First-In, First-Out, FIFO)
队列的核心思想就像现实生活中的排队(例如食堂打饭),最早进入队列的元素将最先被移出。因此,队列也被称为“先进先出”表。

二、 队列的基本操作 (ADT)

一个完整的队列数据结构通常应支持以下基本操作:

  • EnQueue(item): 将元素 item 入队。
  • DeQueue(): 队头元素出队。
  • GetFront(): 获取队头元素的值(不出队)。
  • IsEmpty(): 判断队列是否为空。
  • IsFull(): 判断队列是否已满(主要用于顺序队列)。
  • InitQueue(): 初始化队列。
  • ClearQueue(): 清空队列。

三、 队列的实现方式

队列主要有两种实现方式:顺序存储(数组)和链式存储(链表)。

3.1 顺序队列 (Sequential Queue)

使用一段连续的存储空间(即数组)来实现队列。

1. 基础实现与“假溢出”问题

  • 定义: 使用一个数组 data[MaxSize] 和两个指针 frontrear
    • front: 指向队头元素的下标
    • rear: 指向队尾元素下一个位置的下标
  • 初始状态: front = 0, rear = 0
  • 队空判断: front == rear
  • 入队操作: data[rear] = item; rear++;
  • 出队操作: item = data[front]; front++;
  • 问题: 随着不断地入队和出队,frontrear 指针会一直向后移动。当 rear 到达数组末尾 (rear == MaxSize) 后,即使数组前面因为出队操作已经有了空闲空间,也无法再插入新元素。这种现象称为 “假溢出” (False Overflow)

如上图,虽然 0 到 front-1 的空间都空着,但因为 rear 已到末尾,系统会误判队列已满,无法再利用这些空间。

2. 循环队列 (Circular Queue) - 解决假溢出

为了解决“假溢出”,我们将数组在逻辑上视为一个环形空间。当指针移动到数组末尾时,它会“绕”回到数组的开头。

  • 实现: 通过取模运算 % 来实现环形逻辑。

    • 入队: rear = (rear + 1) % MaxSize;
    • 出队: front = (front + 1) % MaxSize;
  • 队空队满的判断 (重点):
    现在 front == rear 既可能是队空,也可能是队满。有两种主流的解决方法:

    • 方法一:使用计数器 count

      • count 记录队列中元素的个数。
      • 队空: count == 0
      • 队满: count == MaxSize
        这是PPT中介绍的方法,逻辑清晰。
    • 方法二:牺牲一个存储单元

      • 规定队尾指针 rear 的下一个位置是队头 front 时,队列为满。
      • 队空: front == rear
      • 队满: (rear + 1) % MaxSize == front
        这种方法在不引入额外变量的情况下解决了问题,是教科书中更常见的方法。

【机试代码实现 - C++ & Python 循环队列】

以下是采用“牺牲一个存储单元”方法的实现,这在算法竞赛中更常用。

C++ 实现:

#include <iostream>
#include <vector>

class MyCircularQueue {
   
   
private:
    std::vector<int> data;
    int head;
    int tail;
    int capacity;

public:
    MyCircularQueue(int k) {
   
   
        capacity = k + 1; // 牺牲一个单元
        data.resize(capacity);
        head = 0;
        tail = 0;
    }

    bool enQueue(int value) {
   
   
        if (isFull()) {
   
   
            return false;
        }
        data[tail] = value;
        tail = (tail + 1) % capacity;
        return true;
    }

    bool deQueue() {
   
   
        if (isEmpty()) {
   
   
            return false;
        }
        head = (head + 1) % capacity;
        return true;
    }

    int Front() {
   
   
        if (isEmpty()) {
   
   
            return -1; // 或抛出异常
        }
        return data[head];
    }

    bool isEmpty() {
   
   
        return head == tail;
    }

    bool isFull() {
   
   
        return (tail + 1) % capacity == head;
    }
};

Python 实现:

class MyCircularQueue:
    def __init__(self, k: int):
        self.capacity = k + 1  # 牺牲一个单元
        self.data = [0] * self.capacity
        self.head = 0
        self.tail = 0

    def enQueue(self, value: int) -> bool:
        if self.isFull()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱看烟花的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值