一个很常见的面试题,用两个栈 Stack 实现队列 Queue。分别写了最简单最容易想到的做法,和优化后的做法。
最初思路:
Stack 是先进后出 FILO,Queue 是先进先出 FIFO,所以如果想在出队时简单地使用栈的 pop() 方法的话,那么入队时就要保证将元素放到栈底,而不是像 Stack.push(x) 那样放到栈顶,这样就实现了最后放入的最后出来。所以只要将栈中原有元素全部倒出来,放入另一个临时栈中,然后把 x 放到栈底,再将临时栈中的元素倒回来,就 OK 了。
Java 实现:
import java.util.Stack;
public class MyQueue {
Stack<Object> _data = new Stack<Object>();
public void enqueue(Object x){
Stack<Object> temp = new Stack<Object>();
while (!_data.isEmpty()) {
temp.push(_data.pop());
}
_data.push(x);
while (!temp.isEmpty()){
_data.push(temp.pop());
}
}
public Object dequeue() {
return _data.pop();
}
}
当然了,还可以在入队时简单的使用栈的 push(x) 方法,这样就需要在出队时,拿出栈底元素,而非栈顶元素,方法是一样的:
import java.util.Stack;
public class MyQueue {
Stack<Object>_data = new Stack<Object>();
public void enqueue(Object x){
_data.push(x);
}
public Object dequeue() {
Object reval = new Object();
Stack<Object> temp = new Stack<Object>();
while (!_data.isEmpty()) {
temp.push(_data.pop());
}
reval = temp.pop();
while (!temp.isEmpty()){
_data.push(temp.pop());
}
return reval;
}
}
优化:
但是,以上的做法并不高效,因为每进行一次入队/出队操作,都要将元素倒进 temp 再倒回来。更好的做法是,只有到了必要的时候,才进行“倒”的工作。
方法是使用两个栈s1, s2。s1用来入队,s2用来出队,入队时直接调用 s1.push(x),出队时直接调用 s2.pop();但若 s2 为空,此时将 s1 中的全部元素倒给 s2。
此法同样也是通过两个栈的反序,“反反得正”,得到队列顺序,实现了先进的元素先出来,但是只有 s2 “库存”为零,没得给的时候才从 s1 中取元素,提高了效率。
Java 实现:
import java.util.Stack;
public class MyQueue {
Stack<Object> s1 = new Stack<Object>();
Stack<Object> s2 = new Stack<Object>();
public void enqueue(Object x){
s1.push(x);
}
public Object dequeue() {
if (s2.isEmpty()) {
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
}
测试结果:
public class Tester {
public static void main(String[]args) {
MyQueue queue = new MyQueue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
System.out.println(queue.dequeue());
}
}
输出:
1
2
3