用两个栈实现一个队列
一、基本思路
通过使用两个栈来模拟队列的先进先出(FIFO)特性:一个栈用于执行入队操作(将新元素压入栈1),另一个栈用于出队操作(从栈2中弹出元素)。在出队时,如果栈2为空,则将栈1中的所有元素逐一弹出并压入栈2,从而确保出队的顺序与入队顺序一致。
二、队列功能实现
1.入队操作
// 入队操作
void enqueue(const T &item) {
// 将新元素压入栈1
stack1.push(item);
}
2.出队操作
// 出队操作
T dequeue() {
if (isEmpty()) {
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
// 如果栈2为空,将栈1的所有元素移动到栈2
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
// 返回栈2的顶部元素
T item = stack2.top();
stack2.pop();
return item;
}
3.查看队头元素
// 查看队头元素
T peek() const{
if (isEmpty()) {
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
// 如果栈2为空,将栈1的所有元素移动到栈2
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
return stack2.top(); // 返回栈2的顶部元素
}
4.判断队列是否为空
// 检查队列是否为空
bool isEmpty() const {
return stack1.empty() && stack2.empty();
}
三、完整代码及测试
#include <iostream>
#include <stack>
#include <stdexcept>
template <typename T>
class QueueUsingStacks {
public:
// 入队操作
void enqueue(const T &item) {
// 将新元素压入栈1
stack1.push(item);
}
// 出队操作
T dequeue() {
if (isEmpty()) {
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
// 如果栈2为空,将栈1的所有元素移动到栈2
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
// 返回栈2的顶部元素
T item = stack2.top();
stack2.pop();
return item;
}
// 查看队头元素
T peek() const{
if (isEmpty()) {
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
// 如果栈2为空,将栈1的所有元素移动到栈2
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
return stack2.top(); // 返回栈2的顶部元素
}
// 检查队列是否为空
bool isEmpty() const {
return stack1.empty() && stack2.empty();
}
private:
std::stack<T> mutable stack1; // 用于入队
std::stack<T> mutable stack2; // 用于出队
};
int main() {
QueueUsingStacks<int> queue;
queue.enqueue(1); // 入队 1
queue.enqueue(2); // 入队 2
queue.enqueue(3); // 入队 3
std::cout << "Front item: " << queue.peek() << std::endl; // 输出队头元素: 1
queue.dequeue(); // 出队操作
std::cout << "Front item after dequeue: " << queue.peek() << std::endl; // 输出队头元素: 2
std::cout << "Is queue empty? " << (queue.isEmpty() ? "Yes" : "No") << std::endl; // 检查队列是否为空
return 0; // 程序结束
}
代码说明
-
数据结构:
- 使用两个栈(
stack1
和stack2
)来实现队列的功能。
- 使用两个栈(
-
入队操作(enqueue):
- 将元素直接压入
stack1
。
- 将元素直接压入
-
出队操作(dequeue):
- 如果
stack2
为空,将stack1
中的所有元素转移到stack2
,然后从stack2
中弹出顶部元素作为出队元素。 - 如果
stack2
不为空,直接弹出顶部元素。
- 如果
-
查看队头元素(peek):
- 和出队操作类似,首先检查
stack2
是否为空。如果为空,则将stack1
的元素转移到stack2
,然后返回stack2
的顶部元素。
- 和出队操作类似,首先检查
-
检查队列是否为空:
- 当两个栈都为空时,队列被认为是空的。
性能分析
- 使用两个栈的结构使得队列的实现简单且易于理解。虽然单次出队操作可能会有较高的时间复杂度(O(n)),但整体平均时间复杂度为 O(1)。
- 空间复杂度是 O(n),其中 n 是队列中元素的数量。