之前我们谈到验证一个出栈序列是否合法比较容易,简单模拟入栈出栈过程即可。那么如果需要求出所有合法的出栈序列该怎么办呢?
(1)我们之前谈到,合法的出栈序列条件:
对于每个已出栈数之后的且小于此数的数都必须按降序排列。例如1 2 5 3 4。对于5来说,后面的3,4都小于5,可是3,4却是升序的。则肯定不是合法的出栈序列。
由此可以想到我们可以求出所有的全排列,然后从中剔除掉非法序列。显然,当序列的长度增加时,多余的计算太多,效率太低。
(2)模拟入栈出栈过程,每次都有两种选择,要么入栈要么出栈。显然按照递归方式是可行的。但是又有一个问题,一般递归,很少牵扯到递归层次之间数据传送问题。而模拟这个过程时,栈的信息从上层传到下层,最后回到上层时,必然栈的状态早已被下层改了。解决办法就是,下层返回时,回复栈的原状态。这样递归就不会出错了。
代码如下:(如果大家还有更好的算法或写法欢迎大家交流讨论。自我感觉我写的这个不太好)
public class TestStackOut {
private static Stack<String> stack = new Stack<String>();//栈
private static Stack<String> list = new Stack<String>();//待装入栈的序列,也用栈来实现
private static StringBuffer out = new StringBuffer();//输出串
public static void recur(){//递归方法
if(stack.empty() && list.empty()){//栈空,序列也空,则输出
System.out.println(out);
return;
} else if(!stack.empty() && !list.empty()){//栈和序列都不空,要么入栈要么出栈
//选择一:出栈
String str = stack.pop();
out.append(str);
recur();
out.deleteCharAt(out.length() - 1);
//选择二:入栈。 注意:在入栈之前,应该把之前由于出栈而对out,stack,list造成的影响复原。
stack.push(str);
str = list.pop();
stack.push(str);
recur();
str = stack.pop(); //入栈操作完后也得复原。
list.push(str);
} else if(!stack.empty() && list.empty()){
String str = stack.pop();
out.append(str);
recur();
//复原
out.deleteCharAt(out.length() - 1);
stack.push(str);
} else if(stack.empty() && !list.empty()){
String str = list.pop();
stack.push(str);
recur();
//复原
str = stack.pop();
list.push(str);
}
}
public static void main(String[] args) {
list.push("5");
list.push("4");
list.push("3");
list.push("2");
list.push("1");
recur();
}
}