开发者社区> 问答> 正文

1,2,3,4依次进栈,出栈随时,写一算法求出所有可能出栈序列

要求带注释,最好使用C或C++

展开
收起
知与谁同 2018-07-18 15:18:53 3015 0
2 条回答
写回答
取消 提交回答
  • 算了
    2019-07-17 22:55:17
    赞同 展开评论 打赏
  • TA有点害羞,没有介绍自己...
    你要算法,从程序中归纳就行了
    我想到一种方法,可是有点复杂,要用到树的结构,先给你看个程序,是计算n个元素进栈,可能的出栈系列种数
    /*递归求n个元素进栈,可能的出栈系列种数*/
    #define N 4
    int m=0,a=0,b=N;/*m表示种数,a表示栈中元素个数,b表示外面还有需要进栈的个数*/
    main()
    {
    inS(a,b);/*首先入栈*/
    printf("%d",m);
    getch();
    }

    int inS(int a,int b)/*入栈*/
    {
    a++;b--;/*入栈栈中元素+1,栈外元素-1 */
    if(b>0)/*若栈外有元素,可以入栈*/
    inS(a,b);
    if(a>0)/*若栈中有元素,可以出栈*/
    outS(a,b);
    }
    int outS(int a,int b)/*出栈*/
    {
    a--;/*出栈栈中元素-1*/
    if(a==0&&b==0)/*若栈中元素和栈外元素都为0个*/
    {
    m++;/*则此种情况的序列满足条件,种数+1*/
    return;
    }
    if(b>0)
    inS(a,b);
    if(a>0)
    outS(a,b);
    }
    若想输出这些序列,可以建立一个二叉树,二叉树的节点为操作(进栈或出栈),从根节点(第一个入栈)到叶子节点(最后一个出栈)的路径就是每个序列的操作序列,每条路径共有2N个节点,分别为每个元素的入栈和出栈操作,然后通过遍历,将这些节点输出即可
    建立这棵树可以用上面的递归建立,也可以用下面的方法建立
    ①建立一颗深度为2N的满二叉树(根节点深度为1),其中根节点为IN(入栈),其他左子树为IN,右子树为OUT(出栈),这棵树共有2^(2N-1)个叶子节点,用根节点到叶子节点共有2^(2N-1)条路径
    ②保留满足下面条件的路径,其他的剔除
    1)路径从根到叶出现IN和OUT总次数均为N个
    2)路径从根到叶出现 IN次数≥OUT次数(即出栈次数不可能多余入栈次数)

    然后输出保留的每条路径上节点类型为OUT的数据,即是出栈序列

    剔除方法可由下面方法实现
    1根节点赋值为1,
    2节点为IN,则此节点赋值为父节点的值+1,节点为OUT,则此节点赋值为父节点的值-1,
    3剔除节点的值为负数,或值>N的节点,或叶子节点上的值不=0的路径,剩下的就是满足条件的路径

    -------------------------------------------------
    我想到一种方法,可以不用树的结构,只是模拟树,先贴程序
    /*从1到N的顺序入栈,输出所有出栈序列*/
    #include "math.h"
    #define N 4
    main()
    {
    void init(int h[][],int a,int b,int k);
    int i,j,sum,logo,h[1000][2*N+1],s[N],a,b,n;
    int M=pow(2,2*N-1);/*共M条路径,每条有2*N个节点*/
    /*h[i][]为第i条路径的操作序列,其中h[i][0]为一个标志,标志此序列是否满足条件,是则为1,否为0;从h[1]到h[2*N]为操作序列,1表示入栈,-1表示出栈*/
    n=M;/*n为成功的序列计数*/
    /*初始化标志和第一个操作,因为第一个操作必定为入栈操作*/
    for(i=0;i<M;i++)
    {
    h[i][0]=1;/*1表示可以,0表示不可以*/
    h[i][1]=1;
    }/*1表示可以,0表示不可以*/
    init(h,0,M-1,2);/*开始初始化第二个操作,不管是否满足条件的序列,都存入数组h中*/
    /*剔除不符合要求的序列*/
    j=0;/*从第0组至第M组依次检验*/
    while(j<M)
    {
    logo=0;
    sum=0;/*计算从h[][1]开始序列的和值*/
    for(i=1;i<=2*N;i++)
    {
    sum+=h[j][i];
    if(sum>N||sum<0)/*若出现入栈次数大于N,或出栈次数多于入栈次数*/
    {
    logo=1;
    break;/*此序列埠满足条件*/
    }
    }
    if(logo==1||sum!=0)/*sum和值表示入栈总数减出栈总数,若不为0,即入栈总数不等于出栈总数,则此序列不满足条件*/
    {
    h[j][0]=0;/*当前序列的标志为0,表示不满足条件*/
    n--;/*总序列总数-1*/
    }
    j++;
    }
    /*输出各序列的出栈序列,s[]是临时模拟栈的,其中变量a表示栈顶(将要插入元素的位置,即栈顶元素的下一位置),b表示将要入栈的元素*/
    for(j=0;j<M;j++)
    {
    if(h[j][0]==1)/*若序列标志为1*/
    {
    a=0;b=1;
    for(i=1;i<=2*N;i++)
    {
    if(h[j][i]==1&&b<=N)/*若序列操作为1(入栈)*/
    {
    s[a]=b;a++;b++;/*则入栈*/
    }
    if(h[j][i]==-1)/*若序列操作为1(出栈)*/
    {
    printf("%d",s[a-1]);/*输出出栈的元素*/
    a--;/*则入栈*/
    }
    }
    printf("\n");
    }
    }
    printf("ALL %d !",n);/*所有序列数*/
    getch();
    }
    /*递归初始化*/
    /*从a到b前一半赋值为1,后一半赋值为-1,由此可得所有的序列*/
    /*每步操作(从2到2*N步)都可以任意的为入栈,出栈,然后剔除不满足条件的序列(不满足条件包括栈中没有元素还出栈,或入栈总数超过要出栈的个数,或入栈数与出栈数步相等),剔除的程序段在主函数中*/
    void init(int h[1000][2*N+1],int a,int b,int k)
    {
    int i,p=a+(b-a)/2;
    if(k<=2*N)
    {
    for(i=a;i<=p;i++)
    h[i][k]=1;
    for(i=p+1;i<=b;i++)
    h[i][k]=-1;
    init(h,a,p,k+1);
    init(h,p+1,b,k+1);
    }
    }
    2019-07-17 22:55:17
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
数据+算法定义新世界 立即下载
袋鼠云基于实时计算的反黄牛算法 立即下载
Alink:基于Apache Flink的算法平台 立即下载