(翻译)数据结构与算法系列 —— 队列
队列介绍
在这篇教程中,你将学习到什么是队列。也将探索队列在C,C++,Java 和 Python 中的实现。
队列是在编程中是一种有用的数据结构。这就像在电影院外买票排队一样,第一个排队的人会第一个买到票。
队列遵循先进先出的规则 —— 先进去队列的元素会首先出队。
在上面的图片中,因为 1 在 2 的前面进入队列,所以 1 也会首先从队列中移除。遵循先进先出的规则。
在编程术语中,把一个元素放入队列叫做入队(enqueue),从队列中移除元素叫做出队(dequeue)。
我们可以使用任意的编程语言实现队列,像C,,C++,Java,Python 或者 C#,但规范几乎是一样的。
队列的基本操作
队列像一个对象(一种抽象的数据结构 —— ADT),它允许下面的操作:
- Enqueue:添加一个元素在队列尾部
- Dequeue:从队列头部移除一个元素
- IsEmpty:检查队列是否为空
- IsFull:检查队列是否已满
- Peek:获取队列中最前面的元素并且不移除它
队列的工作原理
队列的操作如下:
- 两个指针
FRONT和REAR FRONT指向队列的第一个元素REAR指向队列的最后一个元素- 初始化,设置
FRONT和REAR的值均为 -1
入队操作
- 检查队列是否已满
- 对于第一个元素,将
FRONT的值设置为0 REAR的索引增加1- 将新添加的元素放在
REAR指向的位置
出队操作
检查队列是否为空’
返回FRONT指向的值
FRONT的索引增加1
对于最后一个元素,将FRONT和REAR的值均重置为-1
队列在Python中的实现
# 队列在Python中的实现
class Queue:
def __init__(self):
self.queue = []
# 添加一个元素
def enqueue(self, item):
self.queue.append(item)
# 移除一个元素
def dequeue(self):
if len(self.queue) < 1:
return None
return self.queue.pop(0)
# 显示队列
def display(self):
print(self.queue)
def size(self):
return len(self.queue)
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
q.enqueue(4)
q.enqueue(5)
q.display()
q.dequeue()
print("After removing an element")
q.display()
队列在Java中的实现
// 队列在Java中的实现
public class Queue {
int SIZE = 5;
int items[] = new int[SIZE];
int front, rear;
Queue() {
front = -1;
rear = -1;
}
boolean isFull() {
if (front == 0 && 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只有一个元素,因此我们要在删除这个元素之后重置它 */
else {
front++;
}
System.out.println("Deleted -> " + element);
return (element);
}
}
void display() {
/* 这个函数用于展示队列元素 */
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();
// 空队列不能执行出队操作
q.deQueue();
// 五个元素入队
q.enQueue(1);
q.enQueue(2);
q.enQueue(3);
q.enQueue(4);
q.enQueue(5);
// 第六个元素不能被添加,因为队列已经满了
q.enQueue(6);
q.display();
// deQueue删除第一个输入的元素,即1
q.deQueue();
// 现在队列中只有四个元素
q.display();
}
}
队列在C中的实现
// 队列在C中的实现
#include <stdio.h>
#define SIZE 5
void enQueue(int);
void deQueue();
void display();
int items[SIZE], front = -1, rear = -1;
int main() {
//空队列不能执行出队操作
deQueue();
//五个元素入队
enQueue(1);
enQueue(2);
enQueue(3);
enQueue(4);
enQueue(5);
// 第六个元素不能被添加,因为队列已经满了
enQueue(6);
display();
//deQueue删除第一个输入的元素,即1
deQueue();
//现在队列中只有四个元素
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;
}
}
// 这个函数用于打印队列
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");
}
队列在C++中的实现
// 队列在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 (front == 0 && 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只有一个元素,因此我们要在删除这个元素之后重置它 */
else {
front++;
}
cout << endl
<< "Deleted -> " << element << endl;
return (element);
}
}
void display() {
/* 这个函数用来展示队列 */
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;
//空队列不能执行出队操作
q.deQueue();
//五个元素入队
q.enQueue(1);
q.enQueue(2);
q.enQueue(3);
q.enQueue(4);
q.enQueue(5);
// 第六个元素不能被添加,因为队列已经满了
q.enQueue(6);
q.display();
//deQueue删除第一个输入的元素,即1
q.deQueue();
//现在队列中只有四个元素
q.display();
return 0;
}
队列的局限
从下图中可以看到,在入队和出队之后,队列的大小减少了。
只有当队列被重置时,我们才能添加索引0和1(当所有元素都出队时)。
REAR到达最后一个索引之后,如果我们能够在空闲的位置(0和1)存储其他元素,我们就可以使用空闲的空间了。这种优化了的队列实现称作循环队列。
复杂度分析
使用数组的队列进队和出队操作的复杂度为O(1)。
队列的应用
- CPU调度,磁盘调度。
- 当数据在两个进程之间异步传输时,队列用于同步。例如:IO缓冲区,管道,文件IO等。
- 处理实时系统中的中断。
- 呼叫中心的电话系统使用队列的方式来按顺序等待呼叫的人。