题目描述
已知一个入栈序列,试求出所有可能的出栈序列数目。例如入栈序列为1,2,3,则可能的出栈序列有5种:1 2 3,1 3 2 ,2 1 3,2 3 1,3 2 1。
分析
要求解出栈序列的数目,还算比较容易的。已经有很多文章分析过这个问题,最终答案就是卡特兰数,也就是说n个元素的出栈序列的总数目=C(2n, n) - C(2n, n-1) = C(2n, n) / (n+1)。在博文Catalan数 中提供了好几种求解卡特兰数的方法。
如果不分析求解的通项公式,是否可以写程序求出出栈的序列数目呢?答案是肯定的,下面的一个程序可以求解出栈序列的数目,代码来自网络中某一篇博客,现在记不起出处了,所以不能标明,请原作者见谅。
#include <stdio.h>
/* sum作为全局变量记录共可能多少种情况*/
int sum = 0;
/*
* 描述:递归计算共可能出现的出栈序列,无返回值
* 参数:
* in -- 目前存放于栈中的元素个数
* wait -- 目前还未进栈的元素个数
* out -- 目前已经出栈的元素个数
* num -- 一共有多少个元素
* */
void f(int in, int wait, int out, int num)
{
/* 如果全部元素都出栈,表明有了一种新情况,总数加一*/
if (out == num)
sum++;
/* 否则继续递归衍生新的状态*/
else
{
/* 衍生方法1:让一个元素进栈*/
if (wait > 0)
f(in+1, wait-1, out, num);
/* 衍生方法2:让一个元素出栈*/
if (in > 0)
f(in-1, wait, out+1, num);
}
}
/* 用main函数调用*/
int main()
{
/* 一共有n个元素*/
//int n = 5;
int n;
scanf("%d", &n);
/* 刚开始时栈中有0个元素,有n个元素等待,有0个元素出了栈,共有n个元素*/
f(0, n, 0, n);
printf ("%d\n", sum);
return 0;
}
扩展
上面只是求所有的出栈数目,如果要求所有的出栈序列呢?比如给定入栈序列为1 2 3,要求所有出栈序列。以下内容转自http://blog.youkuaiyun.com/lzshlzsh/article/details/5910682
如下图所示:在每个节点可能有两种操作:进栈,出栈。进栈则转入左子树,出栈则进入右子树。当“未处理”元素为空时,输出序列就已经确定(如图中绿色节点所示)。注意在回退时需要维护输出序列和栈的状态。
#include <iostream>
#include <vector>
#include <iomanip>
using namespace std;
void func(int A[], int j, int n, vector<int> &stk, vector<int> &que)
{
static int cnt = 0;
if (j >= n){
cout << ++cnt << ": ";
for (unsigned int k = 0; k < que.size(); k++){ //打印出栈序列
cout << setw(5) << que[k];
}
for (int k = stk.size() - 1; k >= 0; k--){ //打印栈中序列,注意这里是从后往前打印
cout << setw(5) << stk[k];
}
cout << endl;
return;
}
stk.push_back(A[j]); /*入栈*/
func(A, j + 1, n, stk, que); /*左子树*/
stk.pop_back(); /*退回到当前结点*/
if (!stk.empty()){ /*出栈*/
que.push_back(stk.back());
stk.pop_back();
func(A, j, n, stk, que); /*右子树*/
stk.push_back(que[que.size() - 1]);
que.pop_back();
}
}
int main()
{
int A[] = {1, 2, 3};
vector<int> stk;
vector<int> que;
func(A, 0, sizeof(A) / sizeof(int), stk, que);
return 0;
}