如果有一天你遇到这个问题、切忌浅尝辄止,提问题之人,肯定是想考察你思考问题的深度、头脑灵活清醒程度,一定要深究下去。其实这个问题实现很简单,主要是其中的具体细节难把握。情急之下,的确很难想完整(已排除天资聪颖之辈)。此篇文章只阐述两种思路。
具体思路这篇博客已经写的很详细了,此篇文章只是实现其思想,并指明在并发下情况下,该注意的地方。
(一)第一种方法应该是大多数人看到此题后的自然而然想到的对策。
如上图所示,
入队:将元素压入S1
出队:先把S1的所有元素倒入S2,将S2的头部元素弹出,然后将S2剩余元素再次倒入S1.代码实现如下
import java.util.Stack;
public class CustomQueue<T> {
private Stack<T> stack1=new Stack<T>();
private Stack<T> stack2=new Stack<T>();
public synchronized void enque(T item){
stack1.push(item);
}
public synchronized T deque(){
T result=null;
//把S1的元素倒入
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
//弹出S2栈顶元素
if(!stack2.isEmpty()){
result=stack2.pop();
}
//把S2的元素倒回
while(!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return result;
}
public static void main(String[] args){
final CustomQueue<Integer> customQueue=new CustomQueue<Integer>();
new Thread(new Runnable() {
public void run() {
while(true){
Integer m=customQueue.deque();
if(m!=null){
System.out.println(m);
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for(int i=0;i<1000;i++){
customQueue.enque(i+1);
}
System.out.println(customQueue.stack1.toString());
}
}).start();
}
}
需注意的是入队以及出队方法必须加锁,因为在多线程环境下会造成死循环或者队列元素无序,比如两个线程同时执行入队、出队方法。当出队操作中弹出栈顶元素后,往S1里倒回剩余元素时,因为入队操作同时往S1中添加元素,所以会出现【3,2,1,5,6,7】,显然是无序的数据。
此种思想有一个小细节的改善,就是当把S1中的元素倒入S2时,可以只倒入S1.size()-1的元素,直接把剩余的那一个元素弹出即可。deque()方法可以如下改善。
public synchronized T deque(){
T result=null;
if(!stack1.isEmpty()){
for(int i=0;i<stack1.size()-1;i++){
stack2.push(stack1.pop());
i--;
}
result=stack1.pop();
}
while(!stack2.isEmpty()){
stack1.push(stack2.pop());
}
return result;
}
(二)第二种方法
1)入队时,将元素压入s1。
2)出队时,判断s2是否为空,如不为空,则直接弹出顶元素;如为空,则将s1的元素逐个“倒入”s2,把最后一个元素弹出并出队。这个思路,避免了反复“倒”栈,仅在需要时才“倒”一次。
import java.util.Stack;
public class CustomQueue<T> {
private Stack<T> stack1=new Stack<T>();
private Stack<T> stack2=new Stack<T>();
public synchronized void enque(T item){
stack1.push(item);
}
public synchronized T deque(){
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
if(!stack2.isEmpty()){
return stack2.pop();
}
return null;
}
}