出栈数目

题目描述

已知一个入栈序列,试求出所有可能的出栈序列数目。例如入栈序列为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;  
}  


 



 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值