功能需求
在一个类中,定义两个公共访问的栈,这两个栈通过交互形成一个队列,保持先进先出的特点并且支持入栈add、poll、peek的操作。同时算法复杂度不能太高。
详细解析
栈的特点是先进后出,而队列的特点是先进先出,我们把两个栈首尾相接起来,一个压入栈,一个弹出栈,就可以实现相应的队列的操作。具体实现是定义一个压入栈stackPush,在压入数据时只往这个栈中压入数据和一个退出栈stackPop弹出数据只从这个栈中弹出,分别对应队列的入列和出列。
因为数据压入栈的时候,顺序是先进后出的。那么只要吧stackPush的数据在压入stackPop中,顺序就变了回来。例如,将1~5依次压入stackPush栈中,那么在stackPush栈中栈顶到栈底依次为5~1,将此时的5~1倒入stackPop中,那么stackPop栈中从栈顶到栈底的数据就会依次是1~5.再从stackPop弹出时,就会像队列一样,其效果图如下
这样看起来是非常简单的,实际上的要求将会有以下两点:1、stackPush中的数据必须要一次性全部压入stackPop中;2、如果stackPop栈中已经存在元素数据,是不能给stackPop栈中压入数据的。这两点都是会导致错误的。
如果违反了1原则:举个例子,1~5依次压入stackPush,stackPush栈顶到栈底的元素分别为5~1,从stackPush压入stackPop栈中时,只将栈顶的5和4压入stackPop,stackPush栈还有3,2,1三个元素存在没有压入。此时用户想要弹栈操作,那么4将先被弹出。这样与预想的队列顺序就不一致了。
如果违反了规则2:将1-5依次压入stackPush栈中,stackPush栈中从栈顶到栈底依次为5~1,stackPush栈中的元素全部倒入stackPop栈中压栈处理,所以stackPop栈中的元素从栈顶到栈底依次为1~5,又在此时压入6~10到stackPush,stackPop不为空,stackPush不能将其数据压入stackPop。如果违反了强行压入,那么stackPop栈中从栈顶到栈低的元素就会变为6~10,1~5,那么此时再弹出栈中元素就会把6先弹出栈,不符合队里的规则。
在调用add(), poll(),peek三种方法中任何一种发生时"压入"元素时的行为都是可以的,前提条件是不违反以上两点。具体请看以下代码:
代码实现
package com.hekaikai666.test2;
import java.util.Stack;
/**
*
* @author hekaikai666
* @time 2018年8月23日下午8:40:35
**/
public class StackTo {
// 栈一存储数据
private Stack<Integer> stackPush;
// 栈二存储栈一中出来的数据
private Stack<Integer> stackPop;
/**
* 单例模式实例化栈(构造方法)
*/
public StackTo() {
super();
this.stackPush = new Stack<Integer>();
this.stackPop = new Stack<Integer>();
}
/**
* poll()方法操作栈中数据
*/
public int poll() {
// 判断两个栈是否都为空
if (stackPop.isEmpty() && stackPush.isEmpty()) {
// 抛出一个运行时异常
throw new RuntimeException("Your Stack is empty");
// 如果只有存入栈为空
} else if (stackPop.isEmpty()) {
// 循环弹出stackPush中的元素并压入stackPop栈中,知道stackPush栈为空
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
// 返回此栈值
return stackPop.pop();
}
public int peek() {
// 判断两个栈是否都为空
if (stackPop.isEmpty() && stackPush.isEmpty()) {
// 抛出一个运行时异常
throw new RuntimeException("Your Stack is empty");
// 如果只有存入栈为空
} else if(stackPop.isEmpty()) {
// 循环弹出stackPush中的元素并压入stackPop栈中,知道stackPush栈为空
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
// 返回此栈值
return stackPop.peek();
}
}
总结分析
我们都能想到两个先进先出的栈首尾相接能实现一个队列,但是在这两个栈中的细节,比如说他们要是没有完全弹出元素,那么会导致栈种元素混乱,之后就不符合队列的要求了,其实实现很简单,思想很重要