要用两个栈实现一个队列,可以利用“栈”的后进先出 (LIFO) 特性来模拟“队列”的先进先出 (FIFO) 操作。具体做法是使用两个栈:一个作为入栈栈,另一个作为出栈栈。
算法步骤
- 入队操作(enqueue): 将元素压入“入栈栈”。
- 出队操作(dequeue): 如果“出栈栈”为空,就将“入栈栈”中的所有元素逐个弹出并压入“出栈栈”,然后从“出栈栈”弹出栈顶元素。否则,直接从“出栈栈”弹出栈顶元素。
这种方法确保了队列的先进先出(FIFO)特性。
Java 实现
import java.util.Stack;
public class QueueWithTwoStacks<T> {
// 入栈栈,用于接收新元素
private Stack<T> stackIn;
// 出栈栈,用于弹出元素
private Stack<T> stackOut;
// 构造函数
public QueueWithTwoStacks() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
// 入队操作,将元素压入入栈栈
public void enqueue(T item) {
stackIn.push(item);
}
// 出队操作,从出栈栈弹出元素
public T dequeue() {
// 如果出栈栈为空,则将入栈栈的元素倒入出栈栈
if (stackOut.isEmpty()) {
if (stackIn.isEmpty()) {
throw new RuntimeException("Queue is empty");
}
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
// 获取队列头部元素,但不出队
public T peek() {
if (stackOut.isEmpty()) {
if (stackIn.isEmpty()) {
throw new RuntimeException("Queue is empty");
}
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.peek();
}
// 判断队列是否为空
public boolean isEmpty() {
return stackIn.isEmpty() && stackOut.isEmpty();
}
public static void main(String[] args) {
QueueWithTwoStacks<Integer> queue = new QueueWithTwoStacks<>();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
System.out.println(queue.dequeue()); // 输出 1
System.out.println(queue.peek()); // 输出 2
System.out.println(queue.dequeue()); // 输出 2
queue.enqueue(4);
System.out.println(queue.dequeue()); // 输出 3
System.out.println(queue.dequeue()); // 输出 4
}
}
解释:
- 两个栈:
stackIn
是用于入队的栈,stackOut
是用于出队的栈。 - 入队操作: 元素被直接压入
stackIn
,这保证了入队的顺序。 - 出队操作: 当
stackOut
为空时,将stackIn
中的所有元素倒入stackOut
,以便反转元素顺序,使其符合队列的 FIFO 特性。
这样,你就可以使用两个栈来实现一个队列,且满足队列的基本功能。