给定入栈顺序,输出所有可能出栈情况及所有情况的总数

一个长度为n的无重复序列入栈的所有出栈方式

例如1、2、3这三个数字,入栈并出栈共有5种方式,分别为:321、312、231、213、123。那么对于长度为n的无重复序列中所有的出栈方式有哪些呢?

为了设计计算的算法,我们可以用队列(queue)来模拟输入,队列的输出则按照原先序列的顺序。使用一个栈(stack)来模拟入栈和出栈,结果保存在另外一个队列(queue)中。

现在的问题来了,怎么样可以实现所有的出栈入栈操作。首先来看看出栈和入栈是怎么回事,对于123这个序列,1先入栈之后有两种选择,1出栈和2入栈,而若2已经入栈之后,在2出栈之前1则不能先行出栈,故对于1我们只需要考虑其在2入栈之前出栈的情况,若1在栈内时2入栈,则1与2只能看成一个整体。

这样就可以用递归的方式求解,伪代码如下:

dostack(输入队列,中间栈,输出队列)

if(输入队列为空)

    if(中间栈为空)

        输出输出队列中的结果

    else

中间栈出栈,放入输出队列

dostack(输入队列,中间栈,输出队列)

else

    if(中间栈非空)

        新建输入队列2、中间栈2、输出队列2

        中间栈2出栈并放入输出队列2

dostack(输入队列2,中间栈2,输出队列2)

    输入队列出队一个数并压入中间栈

dostack(输入队列,中间栈,输出队列)

 

 

其基本思想为对于中间栈的每一个时刻拍照,都递归其后续的所有可能,由于在递归返回的时候还需要递归前的信息,所以每次递归都是新建数据结构而保存当前时刻的状态。若输入队列已经为空,则中间栈只有一种出栈方式,中间栈也为空时递归结束。

 

 

详细代码如下:

输入为序列的长度n,初始化序列为1,2,3…n,而输出则为所有可能的出栈数列。

//输入压栈顺序如1 2 3 4 5 6 7 8 ..n,确定所有可能出栈的得到的结果
//同时计算情况的总数n
#include <stdio.h>
#include <iostream>
#include <stack>
#include <queue>

using namespace std;
//递归法只计算所有情况总数
int getPermuStack(int n, int m)
{
     if(n == 0)//递归边界
     return 1;
     if(m == 0)//(n,0)问题的处理
     return getPermuStack(n-1, 1);
     return getPermuStack(n, m-1) + getPermuStack(n-1, m+1);
}
//Catalan公式法 最多只能算到n=10
long long jiecheng(long long n)
{
    if(n==1) return 1;
    else return n*jiecheng(n-1);
}
long long catalan(long long n)
{
    return (jiecheng(2*n)/jiecheng(n+1)/jiecheng(n));
}
//下面算法函数既输出所有可能压栈(不全压,但仍按给定顺序压栈)的情况,也输出对应的出栈情况及总数
int n,i,j;
int res;
stack <int> s;
queue <int> in,out;
void clear(stack <int> &s)
{
    while(!s.empty())
    s.pop();
}
void clear(queue <int> &s)
{
    while(!s.empty())
    s.pop();
}
void print(queue <int> i)
{
    while(!i.empty())
   {
    cout<<i.front();
    i.pop();
   }
    cout<<endl;
}
void dostack(queue <int> in,stack <int> s,queue <int> out)
{
    if(in.empty())
     {
        if(s.empty())
       {
          res++;
          print(out);
       }
       else
       {
          out.push(s.top());
          s.pop();
          dostack(in,s,out);
       }
    }
    else
    {
       if(!s.empty())
        {
         stack <int> ts;
         queue <int> tin,tout;
         tin=in;
         ts=s;
         tout=out;
         tout.push(ts.top());
         ts.pop();
         dostack(tin,ts,tout);
        }
         s.push(in.front());
         in.pop();
         dostack(in,s,out);
    }
}
int main()
{
      cout<<"请输入1~n共n个数:";
      while(cin>>n)
      {
        res=0;
        clear(in);
        clear(out);
        clear(s);
        for(i=n;i>=1;i--)
              in.push(i);
        dostack(in,s,out);
        cout<<"对应的出栈情况总数="<<res<<endl;

      }
      cout<<"1~n依次进栈时,使用递归函数所有的情况总数:"<<endl;
      for(i=1;i<15;i++)
         cout<<"n="<<i<<"  "<<getPermuStack(i,0)<<endl;

      cout<<endl<<"1~n依次进栈时,使用Catalan公式所有的情况总数:"<<endl;
      for(i=1;i<15;i++)
         cout<<"n="<<i<<"  "<<catalan(i)<<endl;


      return 0;
}

 

 

原文http://blog.csdn.net/zqt520/article/details/8010485

 

 

 
以下是用Java实现输入ABCD四个字母入栈输出全部可能出栈顺序的代码: ```java import java.util.ArrayList; import java.util.Stack; public class StackPermutation { public static void main(String[] args) { char[] input = {'A', 'B', 'C', 'D'}; ArrayList<String> result = new ArrayList<String>(); Stack<Character> stack = new Stack<Character>(); permutation(input, 0, stack, result); for (String s : result) { System.out.println(s); } } public static void permutation(char[] input, int index, Stack<Character> stack, ArrayList<String> result) { if (index == input.length && stack.isEmpty()) { StringBuilder sb = new StringBuilder(); for (char c : input) { sb.append(c); } result.add(sb.toString()); } else { if (index < input.length) { stack.push(input[index]); permutation(input, index + 1, stack, result); stack.pop(); } if (!stack.isEmpty()) { char c = stack.pop(); input[index] = c; permutation(input, index, stack, result); stack.push(c); input[index] = 0; } } } } ``` 该程序使用递归实现了求出所有输入ABCD四个字母入栈后的所有可能出栈顺序。其中,permutation()方法用于递归计算不同的出栈顺序,index参数表示当前处理的字母在输入序列中的下标位置,stack参数表示当前的状态,result参数表示所有不同出栈顺序的列表。在每次递归中,程序分别考虑将当前字母入栈出栈的两种情况,直到处理完所有字母并且为空。最后,程序将所有不同出栈顺序保存到一个ArrayList中并输出
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值