现在的位置: 首页 > 综合 > 正文

[原创]关于a1,a2,a3,…,an共n个元素依次入栈其可能出栈的排列数的计算

2013年09月19日 ⁄ 综合 ⁄ 共 3774字 ⁄ 字号 评论关闭

以前一直以为1,2,3,4依次入栈可能出栈的顺序只有一种,那就是4321,因为一直认为栈是先进后出的,所以.....,最后终于知道事实上在后面的元素入栈之前前面的元素可能会出栈,比如在4入栈之前321就已经依次出栈了,那出栈序列则为3214;那么当每一个元素都满足刚入栈就立即出栈时则出栈序列为1234,这个序列是我当时最想不通的了,因为一直信奉“先进后出”,呵呵。以前对这部分也是很迷糊的,前段时间在编写二叉树的非递归的先序遍历算法时,终于意识到出栈次序的重要性,所以后来好好研究,终于解决了这个问题的一大半

先说下解决这个问题的主要方法:分冶法+递归

 

现考虑a1,a2,a3,...,an共n个元素依次入栈(a1,a2,a3,...,an这n个元素不一定是有序的,或者说这n个元素可以是任意顺序,但是应该必须保证每个元素是唯一的):

设用S(i,n)表示“a1,a2,a3,...,ai,...,an这n个元素中第i个元素ai最先出栈时所有的排列数”,那么当ai出栈后,紧接着ai出栈后的出栈元素必然是{ a(i-1), a(i+1), a(i+2), ... ,a( i + n-i ) }这(n-i+1)个元素中的某一个元素,现在先假设i>1以使a(i-1)有意义——这是因为这n个元素是依次入栈的,所以当ai最先出栈时,必然ai前面的任何一个元素(指的是先于ai入栈的元素)已经入栈并且未曾出栈(因为ai最先出栈),那么紧接着ai出栈的必然是ai后面的元素中的一个(因为后面的元素后入栈,所以可以是任意的元素紧接着ai出栈)或者a(i-1),因为对于前(i-1)个已经入栈但却还未出栈的元素中,必须等到a(i-1)出栈后,a(i-2),a(i-3),...,a1这些元素才有机会出栈,说得土的一点就是,a(i-1)堵住了前面的(i-2)个元素!

 

1、对于a(i-1)紧接着ai出栈时:a(i-1)是{ a1,a2,a3, ..., a(i-1) , a(i+1), a(i+2) , ... , an }共(n-1)个元素第i-1个元素,所以这种情况下所有的出栈的排列数为S( i-1, n-1 )

2、对于a(i+1)紧接着ai出栈时:a(i+1)是{ a1,a2,a3, ..., a(i-1) , a(i+1), a(i+2) , ... , an }共(n-1)个元素第i个元素(注意哦),所以这种情况下所有的出栈的排列数为S( i, n-1 )

3、对于a(i+2)紧接着ai出栈时:a(i+2)是{ a1,a2,a3, ..., a(i-1) , a(i+1), a(i+2) , ... , an }共(n-1)个元素第(i+1)个元素(注意哦),所以这种情况下所有的出栈的排列数为S( i+1, n-1 )

.

.

.

(n-i+1)、对于a( i + n-i )[即an]紧接着ai出栈时:an是{ a1,a2,a3, ..., a(i-1) , a(i+1), a(i+2) , ... , an }共(n-1)个元素第(n-1)个元素(注意哦),所以这种情况下所有的出栈的排列数为S( n-1, n-1 )

 

 

那么根据加法原理,得到:

S(i,n) = S( i-1, n-1 ) + S( i, n-1 ) + S( i+1, n-1 ) + S( i+2, n-1 ) + ... + S( i+ n-1-i , n-1 )

这里共有(n-i+1)个数相加

 

显然当i=1时,前面不可能有元素会紧接着a1出栈(说过有a0这个元素吗?),所以为了i=1时满足上式,规定而且事实上也应该是S( 0, n ) = 0 ,那么当i=n时,显然S( n, n ) = 1 ,因为第n个元素(最后入栈的元素)最先出栈时其他元素都是被前面一个元素堵住了,所以只有一种排列。

 

对于上面的公式:当取i的值为(i+1),则有

S(i+1, n) =  S( i, n-1 ) + S( i+1, n-1 ) + S( i+2, n-1 ) + ... + S( i+ n-1-i , n-1 )

这里共有( n -(i+1) +1) 个数相加

 

二式相减得到:

S( i,n ) - S( i+1, n ) = S( i-1, n-1 ) 即 S(i,n) = S(i-1, n-1) + S(i+1, n )

另外S( 0, n ) = 0 且 S( n, n ) = 1

 

所以这样就能算出S( i,n )

然后是a1,a2,a3, ..., an共n个元素依次入栈后所有的可能出栈的排列数为T(n) , 则

T(n) = S( 1, n ) + S( 2, n ) + S( 3, n ) + ... + S( n-1, n ) + S( n, n )

最终应该求出T(n) , 很遗憾的是在高中时我没能好好学习排列组合知识,所以目前无法用现有的数学运算符来表达出T(n)或S(i,n),或者说我求不出来T(n)或S(i,n),如果有人能够算出来,请通知我一下!

 

所以我只得编写程序求解这个问题了,因为计算机的计算能力很强!

运行结果如下:

1
T(1)=1  1!=1    T(1)/1!=1

1 1
T(2)=2  2!=2    T(2)/2!=1

2 2 1
T(3)=5  3!=6    T(3)/3!=0.833333

5 5 3 1
T(4)=14 4!=24   T(4)/4!=0.583333

14 14 9 4 1
T(5)=42 5!=120  T(5)/5!=0.35

42 42 28 14 5 1
T(6)=132        6!=720  T(6)/6!=0.183333

132 132 90 48 20 6 1
T(7)=429        7!=5040 T(7)/7!=0.085119

429 429 297 165 75 27 7 1
T(8)=1430       8!=40320        T(8)/8!=0.0354663

1430 1430 1001 572 275 110 35 8 1
T(9)=4862       9!=362880       T(9)/9!=0.0133984

4862 4862 3432 2002 1001 429 154 44 9 1
T(10)=16796     10!=3628800     T(10)/10!=0.00462853

16796 16796 11934 7072 3640 1638 637 208 54 10 1
T(11)=58786     11!=39916800    T(11)/11!=0.00147271

58786 58786 41990 25194 13260 6188 2548 910 273 65 11 1
T(12)=208012    12!=479001600   T(12)/12!=0.000434262

208012 208012 149226 90440 48450 23256 9996 3808 1260 350 77 12 1
T(13)=742900    13!=1932053504  T(13)/13!=0.000384513

 

本来用截图做结果,但是可惜不能上传图片,这个程序在gcc和VS2008里面测试通过,关于递归的能否结束,其实只要你注意一下每次递归调用后i的变化就能知道递归是否会最终结束,因为0<= i <=n,注意到这一点就可以很容易了解递归最终会结束,但是我还是不期望以不合法的数据调用函数,在调用函数时请确保0<= i <=n ,由运行结果可以看出T(n)的变化远远没有n!的变化快,因为T(n)只不过是累加的过程,所以尽管S(i,n)被调用多次,但由于每次计算都是加,所以计算还是很快的(0.133s)。注意理解S(i,n)表示“a1,a2,a3,...,ai,...,an这n个元素中第i个元素ai最先出栈时所有的排列数”,这是求解问题和运用递归的关键!现在解决这个问题算是有头绪了,准备再写程序输出所有的可能的出栈序列。

抱歉!评论已关闭.