您的位置:首页 > 其它

两个栈实现一个队列

2013-09-07 22:12 393 查看
建了博客,可是一个字也没写过。今天写这个练手的简单小题目,看看会不会被砖头拍死。两个栈实现一个队列,不考虑效率的确不是什么难事。于是,我懒得做任何优化,只是尽量把代码写干净一点,用Java。接口和java.util.Queue类似(可能不是完全一样):offer方法表示入队,poll方法表示出队,peek方法是提取队头元素,empty方法检测队列是否为空。

思路很简单——我看了题目很快就能想出来思路的,想必是不难。想象两个栈A和B,一开始里面都没有元素。

入队(offer)时,只是在A中压入相应的元素。

出队(poll)时,由于需要的是A底部的元素,所以把A种的元素逐个弹出放入B中,就可以把顺序颠倒过来,使得A的底部元素成为B的顶部元素(ensureDequeue方法和exchangeStack方法)。

访问队列顶部元素(peek)和出队很接近,不用单独说了。

回到入队,如果B不是空的,那么需要和出队相反的操作(ensureEnqueue方法)。布尔变量mEnqueue用来区分当前是处于入队还是出队的状态,这样就可以决定要不要调用exchangeStack方法来”倾倒“某个栈。

import java.util.Stack;

class MyQueue<T> {
private Stack<T> mStackEnqueue;
private Stack<T> mStackDequeue;
private boolean mEnqueue;

public MyQueue() {
mStackEnqueue = new Stack<T>();
mStackDequeue = new Stack<T>();
mEnqueue = true;
}

public void offer(T value) {
ensureEnqueue();
mStackEnqueue.push(value);
}

public T poll() {
ensureDequeue();
if (mStackDequeue.empty()) return null;
return mStackDequeue.pop();
}

public T peek() {
ensureDequeue();
if (mStackDequeue.empty()) return null;
return mStackDequeue.peek();
}

public boolean empty() {
if (mEnqueue) {
return mStackEnqueue.empty();
}
return mStackDequeue.empty();
}

private void ensureEnqueue() {
if (!mEnqueue) {
exchangeStack(mStackDequeue, mStackEnqueue);
mEnqueue = true;
}
}

private void ensureDequeue() {
if (mEnqueue) {
exchangeStack(mStackEnqueue, mStackDequeue);
mEnqueue = false;
}
}

private void exchangeStack(Stack<T> src, Stack<T> dst) {
assert dst.empty();
while (!src.empty()) {
T tmp = src.pop();
dst.push(tmp);
}
}
}

public class Stack2Queue {
public static void main(String[] args) {
System.out.println("Start testing MyQueue");
MyQueue<Integer> myQueue = new MyQueue<Integer>();
assert myQueue.empty();
int length = 10;
// enqueue
for (int k = 0; k < length; ++k) {
myQueue.offer(Integer.valueOf(k));
assert myQueue.peek().intValue() == 0;
assert !myQueue.empty();
}

// dequeue
for (int k = 0; k < length; ++k) {
assert myQueue.peek().intValue() == k;
assert !myQueue.empty();
Integer kWrapped = myQueue.poll();
assert kWrapped.intValue() == k;
}

// dequeue when queue is empty
assert myQueue.empty();
Integer nullInteger = myQueue.poll();
assert nullInteger == null;
assert myQueue.empty();

// interleaved enqueue and dequeue
for (int k = 0; k < length; ++k) {
myQueue.offer(Integer.valueOf(k));
}
for (int k = 0; k < length; ++k) {
myQueue.offer(Integer.valueOf(k + length));
Integer kWrapped = myQueue.poll();
assert kWrapped.intValue() == k;
}
for (int k = 0; k < length; ++k) {
Integer kWrapped = myQueue.poll();
assert kWrapped.intValue() == k + length;
}
System.out.println("Finish testing MyQueue");
}
}


我用了一堆assert来测试,只是因为我好久不用assert了。Java里直接写上assert是不够的,需要把你虚拟机的断言支持打开,网上一搜一堆,不再赘述。写完这段小程序,上网查了一下,发现可以优化的地方还是有的。比如:

mEnqueue这个状态变量可以拿掉,直接用两个栈是否为空来作为判断当前状态的条件。

exchangeStack方法中,不用把某一个栈完全倒空。比如,A中有若干元素,此时需要出队,那么出栈时A中的最后一个元素不用放到B中,直接拿出来就是要出队的元素。这样操作之后,两个栈的状态不会和上面给出的程序有任何不同,但是省了一次入栈操作。

如此等等。但是,我始终觉得这个问题充其量只能练练手,没有实用价值。当你入队N个元素,然后交替进行入队和出队操作,麻烦就来了。因为每一次操作,都需要对Θ(n)个元素做一次出栈和入栈操作,费力不讨好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: