队列数据结构

队列是编程中非常有用的数据结构。它类似于电影院外的排队购票,先进入队列的人最先买到票。

队列遵循先进先出 (FIFO) 规则——先进入队列的元素也是先出队列的元素。

Representation of Queue in first in first out principle
队列的 FIFO 表示

在上图中,由于 1 先于 2 入队,它也是最先出队的。它遵循FIFO规则。

在编程术语中,将元素放入队列称为enqueue(入队),从队列中移除元素称为dequeue(出队)

我们可以在任何编程语言(如 C、C++、Java、Python 或 C#)中实现队列,但规范基本相同。


队列的基本操作

队列是一个对象(一种抽象数据结构 - ADT),它允许进行以下操作:

  • Enqueue(入队):将元素添加到队列的末尾
  • Dequeue(出队):从队列的前端移除元素
  • IsEmpty(判空):检查队列是否为空
  • IsFull(判满):检查队列是否已满
  • Peek(查看):获取队列前端元素的值而不移除它

队列的工作原理

队列操作的工作原理如下:

  • 两个指针 FRONTREAR
  • FRONT 指向队列的第一个元素
  • REAR 指向队列的最后一个元素
  • 初始时,将 FRONTREAR 的值设置为 -1

入队操作

  • 检查队列是否已满
  • 对于第一个元素,将 FRONT 的值设置为 0
  • REAR 索引加 1
  • 将新元素添加到 REAR 指向的位置

出队操作

  • 检查队列是否为空
  • 返回 FRONT 指向的值
  • FRONT 索引加 1
  • 对于最后一个元素,将 FRONTREAR 的值重置为 -1
Demonstrating how front and rear indexes are modified during enqueue and dequeue operations
入队和出队操作

Python、Java、C 和 C++ 中的队列实现

我们通常使用数组在 Java 和 C/C++ 中实现队列。在 Python 中,我们使用列表。

队列可视化:不要只看不练。使用我们新的 DSA 可视化工具,实时查看数据结构的每一行如何一步步工作。 自己试试!

# Queue implementation in Python

class Queue():

    def __init__(self, k):
        self.k = k
        self.queue = [None] * k
        self.head = self.tail = -1

    # Insert an element into the queue
    def enqueue(self, data):

        if (self.tail == self.k - 1):
            print("The queue is full\n")

        elif (self.head == -1):
            self.head = 0
            self.tail = 0
            self.queue[self.tail] = data
        else:
            self.tail = self.tail + 1
            self.queue[self.tail] = data

    # Delete an element from the queue
    def dequeue(self):
        if (self.head == -1):
            print("The queue is empty\n")

        elif (self.head == self.tail):
            temp = self.queue[self.head]
            self.head = -1
            self.tail = -1
            return temp
        else:
            temp = self.queue[self.head]
            self.head = self.head + 1
            return temp

    def printQueue(self):
        if(self.head == -1):
            print("No element in the queue")

        else:
            for i in range(self.head, self.tail + 1):
                print(self.queue[i], end=" ")
            print()


# Your Queue object will be instantiated and called as such:
obj = Queue(5)
obj.enqueue(1)
obj.enqueue(2)
obj.enqueue(3)
obj.enqueue(4)
obj.enqueue(5)
print("Initial queue")
obj.printQueue()

obj.dequeue()
print("After removing an element from the queue")
obj.printQueue()

// Queue implementation in Java

public class Queue {
  int SIZE = 5;
  int items[] = new int[SIZE];
  int front, rear;

  Queue() {
    front = -1;
    rear = -1;
  }

  boolean isFull() {
    if (rear == SIZE - 1) {
      return true;
    }
    return false;
  }

  boolean isEmpty() {
    if (front == -1)
      return true;
    else
      return false;
  }

  void enQueue(int element) {
    if (isFull()) {
      System.out.println("Queue is full");
    } else {
      if (front == -1)
        front = 0;
      rear++;
      items[rear] = element;
      System.out.println("Inserted " + element);
    }
  }

  int deQueue() {
    int element;
    if (isEmpty()) {
      System.out.println("Queue is empty");
      return (-1);
    } else {
      element = items[front];
      if (front >= rear) {
        front = -1;
        rear = -1;
      } /* Q has only one element, so we reset the queue after deleting it. */
      else {
        front++;
      }
      System.out.println("Deleted -> " + element);
      return (element);
    }
  }

  void display() {
    /* Function to display elements of Queue */
    int i;
    if (isEmpty()) {
      System.out.println("Empty Queue");
    } else {
      System.out.println("\nFront index-> " + front);
      System.out.println("Items -> ");
      for (i = front; i <= rear; i++)
        System.out.print(items[i] + "  ");

      System.out.println("\nRear index-> " + rear);
    }
  }

  public static void main(String[] args) {
    Queue q = new Queue();

    // deQueue is not possible on empty queue
    q.deQueue();

    // enQueue 5 elements
    q.enQueue(1);
    q.enQueue(2);
    q.enQueue(3);
    q.enQueue(4);
    q.enQueue(5);

    // 6th element can't be added to because the queue is full
    q.enQueue(6);

    q.display();

    // deQueue removes element entered first i.e. 1
    q.deQueue();

    // Now we have just 4 elements
    q.display();

  }
}
// Queue implementation in C

#include <stdio.h>
#define SIZE 5

void enQueue(int);
void deQueue();
void display();

int items[SIZE], front = -1, rear = -1;

int main() {
  //deQueue is not possible on empty queue
  deQueue();

  //enQueue 5 elements
  enQueue(1);
  enQueue(2);
  enQueue(3);
  enQueue(4);
  enQueue(5);

  // 6th element can't be added to because the queue is full
  enQueue(6);

  display();

  //deQueue removes element entered first i.e. 1
  deQueue();

  //Now we have just 4 elements
  display();

  return 0;
}

void enQueue(int value) {
  if (rear == SIZE - 1)
    printf("\nQueue is Full!!");
  else {
    if (front == -1)
      front = 0;
    rear++;
    items[rear] = value;
    printf("\nInserted -> %d", value);
  }
}

void deQueue() {
  if (front == -1)
    printf("\nQueue is Empty!!");
  else {
    printf("\nDeleted : %d", items[front]);
    front++;
    if (front > rear)
      front = rear = -1;
  }
}

// Function to print the queue
void display() {
  if (rear == -1)
    printf("\nQueue is Empty!!!");
  else {
    int i;
    printf("\nQueue elements are:\n");
    for (i = front; i <= rear; i++)
      printf("%d  ", items[i]);
  }
  printf("\n");
}
// Queue implementation in C++

#include <iostream>
#define SIZE 5

using namespace std;

class Queue {
   private:
  int items[SIZE], front, rear;

   public:
  Queue() {
    front = -1;
    rear = -1;
  }

  bool isFull() {
    if (rear == SIZE - 1) {
      return true;
    }
    return false;
  }

  bool isEmpty() {
    if (front == -1)
      return true;
    else
      return false;
  }

  void enQueue(int element) {
    if (isFull()) {
      cout << "Queue is full";
    } else {
      if (front == -1) front = 0;
      rear++;
      items[rear] = element;
      cout << endl
         << "Inserted " << element << endl;
    }
  }

  int deQueue() {
    int element;
    if (isEmpty()) {
      cout << "Queue is empty" << endl;
      return (-1);
    } else {
      element = items[front];
      if (front >= rear) {
        front = -1;
        rear = -1;
      } /* Q has only one element, so we reset the queue after deleting it. */
      else {
        front++;
      }
      cout << endl
         << "Deleted -> " << element << endl;
      return (element);
    }
  }

  void display() {
    /* Function to display elements of Queue */
    int i;
    if (isEmpty()) {
      cout << endl
         << "Empty Queue" << endl;
    } else {
      cout << endl
         << "Front index-> " << front;
      cout << endl
         << "Items -> ";
      for (i = front; i <= rear; i++)
        cout << items[i] << "  ";
      cout << endl
         << "Rear index-> " << rear << endl;
    }
  }
};

int main() {
  Queue q;

  //deQueue is not possible on empty queue
  q.deQueue();

  //enQueue 5 elements
  q.enQueue(1);
  q.enQueue(2);
  q.enQueue(3);
  q.enQueue(4);
  q.enQueue(5);

  // 6th element can't be added to because the queue is full
  q.enQueue(6);

  q.display();

  //deQueue removes element entered first i.e. 1
  q.deQueue();

  //Now we have just 4 elements
  q.display();

  return 0;
}

队列的局限性

正如您在下图所示,经过一番入队和出队操作后,队列的大小减小了。

the empty spaces at front cannot be used after dequeing from a full queue
队列的局限性

并且只有在队列被重置(所有元素都已出队)后,我们才能添加索引 0 和 1。

REAR 到达最后一个索引后,如果我们能在空出的空间(0 和 1)中存储额外的元素,我们就可以利用这些空的空间。这通过一种称为循环队列的修改队列来实现。


复杂度分析

使用数组实现队列的入队和出队操作的复杂度为O(1)。如果您在 Python 代码中使用pop(N),则复杂度可能为O(n),具体取决于要弹出项的位置。


队列的应用

  • CPU 调度、磁盘调度
  • 当数据在两个进程之间异步传输时。队列用于同步。例如:IO 缓冲区、管道、文件 IO 等
  • 实时系统中中断的处理。
  • 呼叫中心的电话系统使用队列按顺序等待来电者。

推荐阅读

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战