有关堆栈和Catalan数的思考
*
* *
* * *
* * * *
* * * * *
形如这样的直角三角形网格,从左上角开始,只能向右走和向下走,问总共有多少种走法?

问题的由来:编号为 1 到 n 的 n 个元素,顺序的进入一个栈,则可能的出栈序列有多少种?

对问题的转化与思考:n 个元素进栈和出栈,总共要经历 n 次进栈和 n 次出栈。这就相当于对这 2n 步操作进行排列。

一 个模型:一个 n*n 的正方形网格,从左上角顶点到右下角顶点,只能向右走和向下走。问共有多少种走法。如果将向右走对应上述问题的进栈,向下走对应上述问题的出栈,那么,可 以视此模型为对上述问题的具体描述。而解决此问题,只要在总共从左上角到右下角的2n步中,选定向右走的步数,即共有C(n 2n)中走法。

但是存在一个问题,如果走法越过了对角线,那么对应到上述问题是出栈数比入栈数多,这是不符合实际的。

对以上模型进行处理,对角线将以上正方形网格分成两部分,只留下包含对角线在内的下半部分,那么就不会出现越过对角线的问题。而这问题就是开始提出的问题。
-------------------------------------------------------

问题等价于:n个1和n个0组成一2n位的2进制数,要求从左到右扫描,1的累计数不小于0的累计数,试求满足这条件的数有多少?
解答: 设P2n为这样所得的数的个数。在2n位上填入n个1的方案数为 C(n 2n)
不填1的其余n位自动填以数0。从C(n 2n)中减去不符合要求的方案数即为所求。
不合要求的数指的是从左而右扫描,出现0的累计数超过1的累计数的数。

不合要求的数的特征是从左而右扫描时,必然在某一奇数2m+1位上首先出现m+1个的累计数,和m个1的累计数。
此 后的2(n-m)-1位上有n-m个1,n-m-1个0。如若把后面这部分2(n-m)-1位,0与1交换,使之成为n-m个0,n-m-1个1,结果得 1个由n+1个0和n-1个1组成的2n位数,即一个不合要求的数对应于一个由n-1个0和n+1个1组成的一个排列。

反过来,任何一个 由n+1个0,n-1个1组成的2n位数,由于0的个数多2个,2n是偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面的部分,令0 和1互换,使之成为由n个0和n个1组成的2n位数。即n+1个0和n-1个1组成的2n位数,必对应于一个不合要求的数。

用上述方法建立了由n+1个0和n-1个1组成的2n位数,与由n个0和n个1组成的2n位数中从左向右扫描出现0的累计数超过1的累计数的数一一对应。

例如 10100101

是由4个0和4个1组成的8位2进制数。但从左而右扫描在第5位(显示为红色)出现0的累计数3超过1的累计数2,它对应于由3个1,5个0组成的10100010。

反过来 10100010

对应于 10100101

因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应,故有

P2n = C(n 2n)— C(n+1 2n)

这个结果是一个“卡塔兰数”Catalan,在组合数学中有介绍,可以参阅有关资料。

-----------------------------------------------------

是否可以用一种更合乎思维习惯的方式解决这个问题呢
可以把这个问题描述为一个二元组,(n, 0) 表示有n个元素等待进栈, 0 个元素已进栈, 这相当于问题最初的状况. 接着问题转化为(n-1,1). 可以这么说(n,0) = (n-1,1). 而对于(n-1,1)则相当于(n-1,0)+(n-2,2).
(n-1,0)表示栈中的一个元素出栈, (n-2, 2)表示又有一个元素入栈.
把问题一般话,则(n,m)的排列问题可以转化为(n,m-1)+(n-1,m+1) 此时m>=1, 因为必须栈中有元素才可以出栈.当m=0则(n,0)的问题只能转化为(n-1,1). 当问题为(0, m)时得到递归边界,这个问题的解是只有一种排列.

程序如下:

#include <stdio.h>

#define ELEMNUM 6;

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);
}

int main()
{
printf("The total count of stackout permutation is %d.", getPermuStack(6, 0));
return 0;
}

运行结果:
The total count of stackout permutation is 132.

-----------------------------------------------------

上面方法是可行的,但在实际编程中最好不要用递归,这样如果递归次数一多就容易造成栈溢出。你可以试下用较大的参数来调用你的函数,会造成runtime error的。
而 且纯粹的递归会造成大量的重复计算:比如,你在计算getPermuStack(5, 5)的时候计算了getPermuStack(5, 4),然后在计算getPermuStack(5,3)的时候又计算了一遍。当然可以通过动态规划的思想设置一个二维数组来记录计算结果,可是太消耗空 间。
如果直观的方法就能很高效地解决问题的话,就不会有那么多人去从数学上求解了。

递归的致命缺点,也是优点就是把复杂的计算留给机器, 递归往往能迅速简洁的思维求出问题的解, 也许得到的算法是低效的.所以递归应该是一种懒人算法. 而"从数学上求解"应当是指从正向考虑问题的解, 递归是逆向求解.

n 个元素顺序入栈,则可能的出栈序列有多少种?转相关推荐

  1. 栈与队列-之出栈和入栈

    ·栈的概念: -运算只在表的一端进行,一般线性表而言,插入删除都可以在任意一个位置进行的 ·队列:入栈和出栈只能分别在两端中的一边,就是说它在一端入队列,在另外一端当中去出队列.从某种意义上讲栈和队列 ...

  2. 问题-栈S最多能容纳4个元素,现有6个元素按A、B、C、D、E、F顺序进栈,问可能的出栈顺序。...

    住栈的特性:对于取出栈内元素每次只能从栈顶开始取(后进先出(栈满时,只能先出后进)) 由于栈内只能容纳4个元素: 所以 E F不可能第一个出栈: 当栈内少于四个元素时 既可以选择进栈,也可以选择出栈 ...

  3. C语言 数据结构 顺序栈的实现 进栈 出栈 初始化

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.代码实现 前言 顺序栈是栈的顺序实现.顺序栈是指利用顺序存储结构实现的栈.采用地址连续的存储空间(数组)依次存储栈 ...

  4. C语言实现栈的进栈与出栈、输出栈顶元素、元素个数、销毁栈

    /********************************引入头文件**************************************************/ #include&l ...

  5. 数据结构栈的操作,初始化栈,进栈,出栈,读取栈顶元素;

    代码段: #include<stdio.h> #include<stdlib.h> #include<stdbool.h> #include<string.h ...

  6. 类C语言--栈与队列习题:设从键盘输入一整数的序列:a1, a2, a3,…,an,试编写算法实现:用栈结构存储输入的整数,当ai≠-1时,将ai进栈;当ai=-1时,输出栈顶整数并出栈。算法应对异常

    此代码可以正常运行,下附有运行区,是实实在在的类C语言 #include <stdio.h> #include <stdlib.h> #include<string.h& ...

  7. 【C++】【数据结构】顺序栈的基本操作(初始化、入栈、出栈、取栈顶元素、遍历输出栈)的算法实现附全代码

    C++实现顺序栈的算法+步骤(附全代码): 使用c++完成数据结构顺序栈的基本操作,包括(初始化.入栈.出栈.取栈顶元素.遍历输出栈等),可直接编译运行. 顺序栈的定义如下: #define MAXS ...

  8. 实现对顺序表的入栈出栈操作、利用栈将十进制转化成二进制输出【数据结构实验报告】

    文章目录 一.入栈.出栈操作 二.利用栈操作将十进制的数转化为二进制 一.入栈.出栈操作 #include<iostream> using namespace std; #define M ...

  9. 数据结构 -- 栈的基本操作(入栈、出栈、取栈顶元素)

    目录 栈的基本操作(顺序栈) 栈的基本操作(链栈) 栈的基本操作(顺序栈) 初始化栈: #define MAXSIZE 5 typedef struct {int *top;int *base;int ...

  10. n个元素进栈,共有多少种出栈顺序?

    1.基于栈的问题分析 我们把n个元素的出栈个数的记为f(n), 那么对于1,2,3, 我们很容易得出: f(1) = 1     //即 1 f(2) = 2     //即 12.21 f(3) = ...

最新文章

  1. SpringCloud Alibaba微服务实战(二) - Nacos服务注册与restTemplate消费
  2. 用了这么久配置中心,还不知道长轮询是什么?
  3. php源码详解,PHP源码编译详解
  4. 知识储备—01-进程,线程,多线程相关总结
  5. 一休和尚 小布偶 晴天娃娃
  6. WIN2003设完C盘权限后终端连不上。
  7. 如何使用小程序自定义组件功能
  8. PowerDesigner教程系列(二)概念数据模型
  9. 拓端tecdat|Python贝叶斯推断Metropolis-Hastings(M-H)MCMC采样算法的实现
  10. 关于下载excel 解析文件名乱码
  11. API设计指南-RestAPI设计最佳实践
  12. 公司法定代表人通常由谁担任?
  13. aspx 微型_如何使用微型可编程机器人向孩子介绍编码
  14. k8s-学习总结(控制器:RS\Deploy\DS\Job\CJ)
  15. sql中的类型转换---学习
  16. 『强烈推荐2个网站』这才是Win10官方原版正确下载姿势
  17. 做直播能有多赚钱,Python告诉你
  18. 职场饭桌:酒桌上的规矩,与领导吃饭如何谈话
  19. IMCO正品行货机使用问题汇总与解答
  20. asp.net监听输入框值的即时变化onpropertychange、oninput

热门文章

  1. sublimetext text3比较两个文档的不同
  2. 医院信息化服务器配置,医院信息化建设方案(完整).doc
  3. 一周信创舆情观察(9.27~10.10)
  4. 【室内定位】采用TOA借助多个基站与终端之间距离进行目标定位matlab源码
  5. mac u盘重装系统(monterey)
  6. zotero抓取知网文献
  7. 串口仪器控制(下篇)——利用虚拟串口模拟仪器
  8. 第2.2节 串行SPI接口控制PE4312数控衰减器
  9. 如何在 R 中进行 Fisher 精确检验
  10. 《SEM长尾搜索营销策略解密》一一2.5 长尾,互联网时代生存的良药