要使用两个队列实现一个栈,必须利用“队列”的先进先出 (FIFO) 特性来模拟“栈”的后进先出 (LIFO) 操作。具体思路是使用两个队列:一个用于存储元素,另一个用于在每次压栈操作后,辅助元素的重新排列。
算法思路:
- 入栈操作(push): 将新元素添加到“空队列”中,并将另一个队列中的所有元素依次移到该队列,使得新加入的元素处于队首,模拟“栈”的后进先出。
- 出栈操作(pop): 从主队列直接弹出队首元素。
- 栈顶操作(top): 获取主队列的队首元素。
Java 实现
import java.util.LinkedList;
import java.util.Queue;
public class StackWithTwoQueues<T> {
// 两个队列,用于模拟栈
private Queue<T> queue1;
private Queue<T> queue2;
// 构造函数
public StackWithTwoQueues() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
// 入栈操作,将元素压入栈
public void push(T item) {
// 先将新元素加入空的 queue2
queue2.add(item);
// 将 queue1 中的所有元素移到 queue2 中
while (!queue1.isEmpty()) {
queue2.add(queue1.remove());
}
// 交换 queue1 和 queue2
Queue<T> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
// 出栈操作,移除并返回栈顶元素
public T pop() {
if (queue1.isEmpty()) {
throw new RuntimeException("Stack is empty");
}
return queue1.remove();
}
// 获取栈顶元素但不移除
public T top() {
if (queue1.isEmpty()) {
throw new RuntimeException("Stack is empty");
}
return queue1.peek();
}
// 判断栈是否为空
public boolean isEmpty() {
return queue1.isEmpty();
}
public static void main(String[] args) {
StackWithTwoQueues<Integer> stack = new StackWithTwoQueues<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.top()); // 输出 3
System.out.println(stack.pop()); // 输出 3
System.out.println(stack.pop()); // 输出 2
stack.push(4);
System.out.println(stack.pop()); // 输出 4
System.out.println(stack.isEmpty()); // 输出 false
System.out.println(stack.pop()); // 输出 1
System.out.println(stack.isEmpty()); // 输出 true
}
}
解释:
- 两个队列:
queue1
用于模拟栈的主队列,queue2
用于辅助入栈操作。 - 入栈操作:
- 新元素总是先放入
queue2
,然后将queue1
中的所有元素都转移到queue2
,这样新加入的元素就会在queue1
的队首位置,模拟了栈的后进先出 (LIFO) 特性。 - 最后交换
queue1
和queue2
,使得queue1
继续作为主队列。
- 新元素总是先放入
- 出栈操作: 直接从
queue1
的队首移除元素,相当于栈顶元素被弹出。 - 栈顶操作: 返回
queue1
的队首元素,表示当前的栈顶元素。
通过这种方式,可以用两个队列来实现栈的基本功能,且保持了栈的 LIFO 特性。