1-3 队列:数组实现
队列是一种遵循FIFO(先进先出)原则的线性数据结构。第一个插入的元素是第一个被移除的元素。
使用数组声明队列
队列可以使用数组实现,主要有两种方式:
- 无限(或动态增长)数组队列
- 固定大小数组队列
无限(或动态增长)数组队列
我们可以使用概念上无限的数组实现队列,只需维护一个front指针。front指针跟踪第一个有效元素。
入队(Enqueue):在末尾的下一个可用位置插入元素,不需要rear指针。
出队(Dequeue):移除front位置的元素并将front指针递增。
front之前的空间永远不会被重用,与基本数组实现不同,我们在每次出队后不需要移动元素。这确保了入队和出队操作都以O(1)时间运行,设计简单。
局限性:
- 空间浪费:front指针之前的元素永远不会被重用,如果许多元素被出队,内存可能会被浪费。
- 无限数组假设:我们假设数组在概念上是无限的。实际上,内存是有限的,因此非常大的队列可能导致内存问题。
固定大小数组队列
在本文中,我们主要讨论使用固定大小数组实现队列。在这种基于数组的队列中,我们维护:
- 一个固定大小的数组
arr[]来存储元素。 - 一个变量
size来跟踪队列中当前的元素数量。 - 一个变量
capacity来表示队列可以容纳的最大元素数量。
#include <iostream>
class MyQueue
{
// 存储队列元素的数组
int* arr;
// 队列可以容纳的最大元素数量
int capacity;
// 队列中当前的元素数量
int size;
public:
explicit MyQueue(int c)
{
capacity = c;
arr = new int[capacity];
size = 0;
}
~MyQueue()
{
delete[] arr;
}
};
队列操作
入队(插入)
如果空间可用,在队列末尾添加元素;否则会导致溢出条件。
时间复杂度:O(1),空间复杂度:O(1)
void enqueue(int x)
{
if (size == capacity)
{
cout << "Queue Overflow" << endl;
return;
}
arr[size++] = x;
}
出队
从队列前端移除元素;如果队列为空,会导致下溢条件。
时间复杂度:O(n)(因为需要移位),空间复杂度:O(1)
void dequeue()
{
if (size == 0)
{
cout << "Queue Underflow" << endl;
return;
}
for (int i = 1; i < size; i++)
{
arr[i - 1] = arr[i];
}
size--;
}
获取队首元素(查看)
如果不为空返回第一个元素,否则返回-1。
时间复杂度:O(1),空间复杂度:O(1)
int getFront()
{
if (size == 0)
{
cout << "Queue is empty" << endl;
return -1;
}
return arr[0];
}
获取队尾元素
如果不为空返回最后一个元素,否则返回-1。
时间复杂度:O(1),空间复杂度:O(1)
int GetRear()
{
if (isEmpty())
{
cout << "Queue is empty!" << endl;
return -1;
}
return arr[size - 1];
}
判断是否为空
检查队列是否有任何元素。
如果队列为空返回true,否则返回false。
时间复杂度:O(1),空间复杂度:O(1)
bool isEmpty()
{
return size == 0;
}
判断是否已满
检查队列是否已达到最大容量。
如果队列已满返回true,否则返回false。
时间复杂度:O(1),空间复杂度:O(1)
bool isFull()
{
return size == capacity;
}
使用数组实现队列的完整代码
#include <iostream>
class MyQueue {
// 存储队列元素的数组
int* arr;
// 队列可以容纳的最大元素数量
int capacity;
// 队列中当前的元素数量
int size;
public:
explicit MyQueue(int c)
{
capacity = c;
arr = new int[capacity];
size = 0;
}
~MyQueue()
{
delete[] arr;
}
bool isEmpty()
{
return size == 0;
}
bool isFull()
{
return size == capacity;
}
// 在队列末尾添加元素x
void inqueue(int x)
{
if (IsFull())
{
std::cout << "Queue is full!\\n";
return;
}
arr[size] = x;
size++;
}
// 移除队列的前端元素
void iequeue()
{
if (isEmpty())
{
std::cout << "Queue is empty!\\n";
return;
}
for (int i = 1; i < size; i++)
{
arr[i - 1] = arr[i];
}
size--;
}
// 返回队列的前端元素
int getFront()
{
if (isEmpty())
{
std::cout << "Queue is empty!\\n";
return -1;
}
return arr[0];
}
// 返回队列的最后一个元素
int getRear() {
if (isEmpty())
{
std::cout << "Queue is empty!" << endl;
return -1;
}
return arr[size - 1];
}
};
int main()
{
MyQueue q(3);
q.Enqueue(10);
q.Enqueue(20);
q.Enqueue(30);
std::cout << "Front: " << q.getFront() << endl;
q.Dequeue();
std::cout << "Front: " << q.getFront() << endl;
std::cout << "Rear: " << q.getRear() << endl;
q.Enqueue(40);
return 0;
}
输出:
Front: 10
Front: 20
Rear: 30
我们可以注意到出队操作是O(n),这是不可接受的。入队和出队操作都应该有O(1)的时间复杂度。这就是为什么如果我们希望使用数组实现队列(因为数组具有缓存友好和随机访问等优势),我们会使用循环数组实现队列。

浙公网安备 33010602011771号