对于一个栈来说遵循 pop 操作时从栈的顶部取一个元素,对于队列来说 poll 操作时从队列队首取一个元素。所以该题翻译过来就是使用两个栈定义一种先放入的元素,最先被取出的数据结构。
此题应考虑到两种情况,首先最简单的一种情况,假设有 1,2,3,4,5 个元素依次进入自定义的队列,再依次取出。由于是进栈操作都进行完了才进行出栈操作,所以我们只需在元素出队时,将进栈元素倒入另一个空栈中即可。示意图如下:
再一种情况是,如果 add poll 操作是交替进行的,那么如何保证数据结构先进先出的定义呢?比如先放入 1,2,3然后要进行一次取出操作取出 1,随后在进行 add 操作放入4,5,这种情况下如何操作两个栈,才能保证之后再取出的时候元素为 2,3,4,5 顺序?实际上我们只需要保证以下两点就可以:
- 如果 StackA(最开始add元素的那个栈) 要往 StackB 中压入元素,那么必须选择一次性全部压入。
- 无论什么时候从队列中取元素,必须保证元素是从 StackB 中 pop 出的,也就是说,当 StackB 不为空的时候绝不能再次向 StackB 中压入元素
为了方便理解可以看下边这幅图:
明白了需要注意的点后就是该写代码的时候了,需要注意的点在图中已经用红色字体标出了,也就是在存入元素一直往 StackA 中存,取元素是从 StackB 中取,但要注意的是取的时候需要保证 StackB 为空的时候要先将 StackA 中元素一次性压如 StackB 中,在进行从 StackB 中取的操作。
public static class TwoStackQueue<E>{
private Stack<E> stackA;
private Stack<E> stackB;
public TwoStackQueue() {
stackA = new Stack<>();
stackB = new Stack<>();
}
/**
* 添加元素逻辑
* @param e 要添加的元素
* @return 这里只是遵循 Queue 的习惯,这里简单处理返回 true 即可
*/
public boolean add(E e){
stackA.push(e);
return true;
}
/**
* 去除元素的时候需要判断两个地方,StackA & StackB 是否都为空
* StackB 为空的时候将StackA中的元素全部依次压入 StackB
* @return 返回队列中的元素 如果队列为空返回 null
*/
public E poll(){
//如果队列中没有元素则直接返回空,也可以选择抛出异常
if (stackB.isEmpty() && stackA.isEmpty()){
return null;
}
if (stackB.isEmpty()){
while (!stackA.isEmpty()){
stackB.add(stackA.pop());
}
}
return stackB.pop();
}
/**
* peek 操作不取出元素,只返回队列头部的元素值
* @return 队列头部的元素值
*/
public E peek(){
//如果队列中没有元素则直接返回空,也可以选择抛出异常
if (stackB.isEmpty() && stackA.isEmpty()){
return null;
}
if (stackB.isEmpty()){
while (!stackA.isEmpty()){
stackB.add(stackA.pop());
}
}
return stackB.peek();
}
}