数据结构——栈—出栈顺序的可能情况

来源:互联网 发布:淘宝转盘抽奖怎么做 编辑:程序博客网 时间:2024/06/14 09:25

        这是一个大一在计算机导论上就提出的问题,在给定待入栈元素顺序(可以中途出栈)的情况下,有多少中情况?当时看了一篇有关的博客,其中用了动态规划的思想解决了这个问题:

        设有f(n)种情况;考虑第一个元素1出栈的位置,若在第一个出栈,则只需考虑剩下n-1个元素的出栈情况,即f(n-1),若第二个出栈,前面有一个元素已经出栈(只能是2),后面有n-2个元素待入栈,则有f(1)*f(n-2)情况;若第三个出栈,前面有2个元素已经出栈(只能是2、3),后面有n-3个元素待入栈,则有f(2)*f(n-3)情况;

所以得到递归方程(n) = f(0)*f(n-1) + f(1)*f(n-2) + ... + f(n-1)*f(0)

      这个式子也可以用组合数计算出来,结果是C_{n}={\frac {1}{n+1}}{2n \choose n}={\frac {(2n)!}{(n+1)!\,n!}}=\prod \limits _{k=2}^{n}{\frac {n+k}{k}}\qquad {\mbox{ for }}n\geq 0.


     但是要输出所有情况不能用这种方法输出

下面给出代码实现:

package popAll;    import java.util.Stack;  import java.util.Scanner;  /*  要讨论所有元素可能的出入栈顺序,思想与计算可能的出入栈顺序情况不同,后者是用动态规划的思想,  将规模为n的情况转化为n个规模为n-1的情况从而实现递归,但是前者要输出每一种具体情况,用动态  规划就不太适合。当第一个元素入栈后,可以出栈或者进栈,所以这有两个选择,不停的重复这两个选  择,直到输入序列和栈中序列都为空就完成了一种情况。所以只要先选一种选择,当完成这种选择后面  的操作后,恢复之前的状态,进行下一次选择,就可得到全都情况,这是一种回溯的思想。  */  public class popAll {      int amount = 0;//统计可能情况数目        int getAmount() {//返回数目          return amount;      }        void outPut(Stack<Integer> outSeq)// 输出可能序列      {          amount++;          Integer temp;          Stack<Integer> alternative = new Stack<Integer>();          //这个过程有两个作用,一举两得          //由于输出出栈顺序需要把输出序列的栈全部输出一遍,这个过程完成后输出胡序列会变为空,所以要用另一栈来接收输出序列中的元素          //而且由于出栈的情况是储存在栈中,要从头输出出栈情况必须先将栈中元素全部反过来再从栈尾输出;          //但是储存出栈序列用数组存起来 会不会更方便?          while (!outSeq.empty())              alternative.push(outSeq.pop());          while (!alternative.empty()) {              temp = alternative.pop();              System.out.print(temp);              outSeq.push(temp);          }          System.out.println();        }        void iniStack(Stack<Integer> stack, Integer n) {//初始化入栈序列,分别用从1到n的元素来标记元素及元素入栈顺序          for (int i = n; i > 0; i--)              stack.push(i);      }        void allPopSeq(Stack<Integer> inSeq, Stack<Integer> inStack, Stack<Integer> outSeq) {          if (inSeq.empty() && inStack.empty())              outPut(outSeq);          else {              if (!inSeq.empty())// 选择入栈              {                  Integer temp = inSeq.pop();// 保存并入栈                  inStack.push(temp);                  allPopSeq(inSeq, inStack, outSeq);// 进行下一选择                  inStack.pop();                  inSeq.push(temp);// 恢复到之前状态              }              if (!inStack.empty()) {                  Integer temp = inStack.pop();// 保存并出栈                  outSeq.push(temp);                  allPopSeq(inSeq, inStack, outSeq);// 进行下一选择                  outSeq.pop();                  inStack.push(temp);// 恢复到之前状态              }          }      }        public static void main(String[] args) {          Integer n;          Stack<Integer> inSeq = new Stack<Integer>();// inSeq准备入栈序列          Stack<Integer> inStack = new Stack<Integer>();// inStack栈中序列          Stack<Integer> outSeq = new Stack<Integer>();// outSeq输出序列          popAll seq = new popAll();          Scanner scan = new Scanner(System.in);          System.out.println("请输入入栈序列中数据个数");         n = scan.nextInt();          seq.iniStack(inSeq, n);          System.out.println("可能的序列为:");          seq.allPopSeq(inSeq, inStack, outSeq);          System.out.println("共" + seq.getAmount() + "种情况");      }  } 


      那么如何判断给定的一个序列是否为可能的出栈序列呢?

下面给出代码实现:


import java.util.Stack;import java.util.Scanner;/*通过模拟入栈的情况来判断序列是否为可能的出栈序列;从给出的序列第一个开始,依次压栈比较当前栈顶元素与出栈序列中的元素,如果相同,查看下一个出栈序列中的元素并出栈,直到序列检查完,则是可能的情况;如果不同,继续压栈,直到所有元素都压进栈还不符合,则是不可能的情况 */public class JudgeStack {void iniArray(Stack<Integer> stack,int n)//初始化用于判断比较的栈{for(int i=n;i>0;i--)stack.push(i);}boolean judge(int n,int array[]) {//开始判断int i=0;Stack<Integer> inPutSeq=new Stack<Integer>();//待输入序列Stack<Integer> inStack=new Stack<Integer>();//栈中iniArray(inPutSeq,n);while(i<n)//最后一位判断完后自动跳出循环{if(inStack.empty())//栈中没元素时要先从待输入序列中压一个进去inStack.push(inPutSeq.pop());if(array[i]!=inStack.peek()&&!inPutSeq.empty())//当前情况与期望不符且待输入序列不为空时继续压栈{inStack.push(inPutSeq.pop());continue;//此时一定要跳出这次循环,不然当待输入序列为空时无法进行最后一次比较}else if(array[i]==inStack.peek())//当前为与期望相符,{inStack.pop();i++;continue;}if(inPutSeq.empty())//当前情况与期望不符且待输入序列为空时跳出,此时一定不是可能的出栈顺序break;}if(i==n)return true;else return false; }public static void main(String[] args){JudgeStack judge=new JudgeStack();boolean isStack;int n;String str;Scanner scan=new Scanner(System.in);System.out.println("请输入待检查数列(默认从1到n为待入栈序列):");str=scan.nextLine();char chars[]=str.toCharArray();int array[]=new int[str.length()];for(int i=0;i<str.length();i++)//将输入字符串转化为整型数组array[i]=(int)(chars[i]-48);n=str.length();isStack=judge.judge(n,array);System.out.println(isStack);}}


原创粉丝点击