出栈序列与Catalan 0-1序列

        出栈序列与Catalan 0-1序列

设集合 N 中的元素按次序1,2,3,...,n 入栈,其所有不同的出栈序列的集合为Sn,则|Sn|=

1、结果证明:

  定义1、 集合 N={1,2,3,...,n}中的元素按一定次序入栈,其每个出栈序列是 N 的一个元排列,若 N 的两个元排列不同,则称为两个不同的出栈序列(栈序列),记栈序列集为 Sn

  定义2、 n个0和n个1组成2n位0-1序列,若对任意i(i=1,2,3,...,2n),序列前i项中1的个数不少于0的个数,则称此序列为Catalan 0-1序列,记Catanlan 0-1序列集为Tn

  定义3、 集合 N={1,2,3,...,n}的一个n元排列,若对任意i,j(j=1,2,3,...,n,且j>i),如j排在i之前,要么j与i相邻,要么j与i之间所排的任一数均大于i,则称该排列为N的栈排列,记栈排列集为Pn

  引理 Tn

  证明:由于在2n位上填入n个1,不填1的其余n位自动填0的序列个数是,从中减去不符合要求的序列数即为所求Tn。不符合要求的序列是指:从左到右扫描,出现0的个数超过1的个数的序列。

  不符合要求的序列在从左向右扫描时,必然在某一奇数2m+1位上首先出现m+1个0的累计数和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,那么便得到一个由n+1个0和n-1个1组成的2n位0-1序列。即一个不符合要求的序列对应于一个由n+1个0和n-1个1组成的一个排列。反之,任何一个由n+1个0和n-1个1组成的2n位0-1序列,由于0的个数多2个,2n是偶数,故在某一个奇数位上出现0的累计数超过1的累计数,同样在后面的部分,令0和1互换,使之成为一个由n个0和n个1组成的2n位0-1序列。也就是说,我们建立了不符合要求的序列n+1个0和n-1个1组成的2n位0-1序列之间的一一对应关系。

  而由n+1个0和n-1个1组成的2n位0-1序列共有

  因此,Tn

     定理1、集合 N={1,2,3,...,n}的n个元素按次序1,2,3,...,n入栈时,Sn

  证明:1):Sn到Tn存在单射:设集合N={1,2,3,...,n}中的元素按一定次序1,2,3,...,n入栈,对Sn中的任一出栈序列,可以用Tn中唯一一个Catalan 0-1序列描述其出栈过程。按照“入栈记1,出栈记0”的原理顺序可得一个长为2n的Catanlan 0-1序列,且具有唯一性。具体方法为:对任意i(i=1,2,3,...,n),设i在某个出栈序列中排在第j个位置(从左起)上,且在出栈序列的前j项中最大数为m,则在2n为0-1序列的第j+m个位置(从左起)上记0,这样,可以在n个位置上记0,其余位置均记1。如:1,2,3,4,5顺次入栈,出栈序列21453对应的0-1序列为1100110100。

  2):Sn到Tn存在满射。对Tn中每一个Catalan 0-1序列,从左到右,看成集合中的元素按1,2,3,...,n入栈时,入栈出栈的过程记录。按照“1看成入栈操作,0看成出栈操作”可唯一写出Sn中一个出栈序列,具体方法为:把0-1序列从左第一个1起上方写1,2,3,...,n;然后把序列的每个0(从左到右)与其左边最近的1配对,相应的1上方的数依次构成一个出栈序列。如:1100110100,其配对为:,因此,对应的唯一的出栈序列为2,1,3,4,5。故Sn到Tn存在一个双射。即:Tn=Sn

  由上面的分析,可以写出出栈序列与Catalan 0-1序列相互转换的程序,以下是我用写的C++代码:

#include  < cstdlib >
#include 
< iostream >
#include 
< iterator >
#include 
< stack >
#include 
< vector >

using   namespace  std;

vector
< int >   Map2Stack( vector < char >&  list ) {
      
int   i, count=0, j=0;
      vector
<int> out(list.size()/2);
      stack
<int>  s;
      
for( i=0; i<list.size(); ++i )
           
if( list[i]=='1' )
               s.push( 
++count );
           
else
               
out[j++]=s.top(), s.pop();
      
return out;
}
     
      
vector
< char >   Map2Catan( vector < int >&  list ) {
      
int   i, Max=0;
      vector
<int>   index(list.size()+1), Max_index(list.size()+1);
      vector
<char>  catanlan(2*list.size(),'1');
      
for( i=0; i<list.size(); ++i ){
           index[list[i]]
=i+1;//list[i]排在第i+1位
           if( list[i]>Max )
               Max
=list[i];
           Max_index[i
+1]=Max;//前i+1位的最大数为Max
      }

      
for( i=0; i<list.size(); ++i )
           catanlan[list[i]
+Max_index[list[i]]-1]='0';
      
return  catanlan;
}


int  main( int  argc,  char   * argv[]) {
    
int   list[]={2,1,4,5,3};
    vector
<int>  e(list,list+sizeof(list)/sizeof(list[0]));
    vector
<char> r1=Map2Catan( e );
    copy( r1.begin(), r1.end(), ostream_iterator
<char>(cout) );
    cout
<<endl;
    vector
<int>  r2=Map2Stack( r1 );
    copy( r2.begin(), r2.end(), ostream_iterator
<int>(cout,"  ") );
    cout
<<endl;
    system(
"PAUSE");
    
return EXIT_SUCCESS;
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值