入栈出栈的问题(汇总)

判断一个入栈出栈的顺序释放符合条件:

输入两个序列表:一个是压栈的顺序列表 arr   第二个是输出的结果列表  result

判断输出的结果列表符不符合压栈出栈条件:

#include <iostream>
#include <stack>
using namespace std;
stack<int> st_f;
int justy(int *arr,int *result){
    int i,j=0;
 for(i=0;i<5;i++){//遍历每一个结果result
    for(int temp=j;temp<5;temp++){//在入栈顺序的数组arr中找到当期与result数组对应的数
       if(result[i]==arr[temp])//如果找到了,那就把result匹配数和在他之前的全部入栈
      {
     for(int temp2=j;temp2<=temp;temp2++)
         st_f.push(arr[temp2]);
      j=temp+1;//把入栈顺序数组进行标记
      break;
   }
    
    }
  if(!st_f.empty()&&st_f.top()==result[i])//如果辅助的栈没为空,并且它有与result【i】相等
     {                                    //就弹出,表示符合条件
       st_f.pop();
     }
  else if(!st_f.empty()&&st_f.top()!=result[i]) {//表示不符合条件
            //cout<<"push's can't success";
            return 0;
             }   
 }
 if(!st_f.empty()) return 0;//如果到了最后辅助栈不为空,也是不符合条件的。
 return 1;
}
int main(){
   int arr[5]={1,2,3,4,5};
   int result[5]={4,5,3,2,1};
   if(justy(arr,result))
      cout<<"stack's reult is ture";
   else
       cout<<"stack's is false";
return 0;
}

最找到牛人分析编号为 1 到 n 的 n 个元素,顺序的进入一个栈,则可能的出栈序列有多少种?就转载了:如下

近日在复习数据结构,看到栈的时候,发现1个元素进栈,有1种出栈顺序;2个元素进栈,有2种出栈顺序;3个元素进栈,有5种出栈顺序,那么一个很自然地问题就是n个元素进栈,共有多少种出栈顺序?


说来惭愧,以前学数据结构的时候竟然没有考虑过这个问题。最近在看动态规划,所以“子问题”这3个字一直在我脑中徘徊,于是解决这个问题的时候我也是用类似“子问题”的方法,说白了就是递推公式。


我们把n个元素的出栈个数的记为f(n), 那么对于1,2,3, 我们很容易得出:


                                     f(1) = 1     //即 1

                                     f(2) = 2    //即 12、21

                                     f(3) = 5     //即 123、132、213、321、231


然后我们来考虑f(4), 我们给4个元素编号为a,b,c,d, 那么考虑:元素a只可能出现在1号位置,2号位置,3号位置和4号位置(很容易理解,一共就4个位置,比如abcd,元素a就在1号位置)。

分析:


 1) 如果元素a在1号位置,那么只可能a进栈,马上出栈,此时还剩元素b、c、d等待操作,就是子问题f(3);

 2) 如果元素a在2号位置,那么一定有一个元素比a先出栈,即有f(1)种可能顺序(只能是b),还剩c、d,即f(2),     根据乘法原理,一共的顺序个数为f(1) * f(2);

 3) 如果元素a在3号位置,那么一定有两个元素比1先出栈,即有f(2)种可能顺序(只能是b、c),还剩d,即f(1),

    根据乘法原理,一共的顺序个数为f(2) * f(1);

 4) 如果元素a在4号位置,那么一定是a先进栈,最后出栈,那么元素b、c、d的出栈顺序即是此小问题的解,即         f(3);


结合所有情况,即f(4) = f(3) + f(2) * f(1) + f(1) * f(2) + f(3);

为了规整化,我们定义f(0) = 1;于是f(4)可以重新写为:

f(4) = f(0)*f(3) + f(1)*f(2) + f(2) * f(1) + f(3)*f(0)


然后我们推广到n,推广思路和n=4时完全一样,于是我们可以得到:

f(n) = f(0)*f(n-1) + f(1)*f(n-2) + ... + f(n-1)*f(0)


 



但这只是一个递推公式(若编程实现,需要维护一个一维数组,时间复杂度为O(n^2))。怎么把它转化为通项公式呢,复杂度仅为O(1)?


于是上网搜索一下,原来真的有这么一个公式:C(2n,n)/(n+1) (C(2n,n)表示2n里取n),并且有个名字叫Catalan数。附上wiki的链接,写得太详细了:http://en.wikipedia.org/wiki/Catalan_number  


现在的问题就是:怎么从上述的递推公式求出C(2n,n)/(n+1) ? 有兴趣的朋友欢迎留言讨论!

//2013.6.4 update
根据网友u010896627的思路,我抽象了下问题,在知乎上问了个问题,其中有一个答案提出了“折现法”,从几何上推出了“n个元素进栈有多少个出栈顺序”这个问题的答案是C(2n,n)-C(2n,n-1),化简一下即得Catalan number。推荐大家看一看。http://blog.csdn.net/johnny710vip/article/details/6930083
 

 //输出全部的可能性

//思路:这里有开始的栈input ,压入的栈 s,准备输出的栈 output       那么就可以通过对这三个栈进行处理就能得到结果;

             1.

stacksqe(&input,&s,&output){

  if  input is empty

      把s中的栈全放入output栈中,然后输出

else   //有两种情况 的操作:1.看看s栈中有没有栈,如果有栈进行出栈放到output中,然后调用stacksqe继续递归      2.进行入栈  让input中的元素继续入栈 s中 ,然后调用stacksque继续递归                  这得注意的是: 这两种可能时要求stacksqe中的input,s,output独立,不相互影响,所以要有副本来进行控制;(这样是用递归的时候要注意的事情,多个可能性的情况下,要注意各自的状态的正确性)

 

}

 

#include <stdio.h>
#include <malloc.h>
typedef   struct{
 int   *stk;
  int   top;
   int   size;
}stack;
void initstack(stack   *s,   int   n) {
 s-> stk   =   (int*)malloc((s-> size=n)   *   sizeof(int));
  s-> top   =   0;
}
void copystack(stack   *ss,   stack   *s)   {
        int   i;
        if(ss-> stk)   free(ss-> stk);
        ss-> stk   =   (int*)malloc((ss-> size=s-> size)   *   sizeof(int));
        ss-> top   =   s-> top;
  for(i=s->top-1;i>=0;i--) 
   ss->stk[i]=s->stk[i];
}
void   outputstack(stack*   s)   {
        int   i;
        for(i=0;i<s-> top;i++)   printf("%2d",s-> stk[i]);
        printf("\n");
}
int   stackempty(stack*   s)   {
        return   !s-> top;
}
void   push(stack*   s,   int   x)   {
        s-> stk[s-> top++]   =   x;
}
int   pop(stack*   s)   {
        return   s-> stk[--s-> top];
}
void   stackseq(stack   *input,   stack   *s,   stack   *output)   {
        /*初始状态:栈input中存放要输入的元素,s,   output为空
            结束状态:input   和   s   均为空                                           */

        stack   ii,   ss,   oo;

       ii.stk=ss.stk=oo.stk=NULL;//必须要初始化,因为如果没有初始化那么就会使得数没定义,会出错
        if(stackempty(input))   {       /*如果数据已经全部输入完毕*/  
               while(!stackempty(s)){
          push(output,pop(s));
       }
       outputstack(output);
        }
        else   {     /*还有元素要输入*/
                if(!stackempty(s))   {     /*我们需要保存现有状态*/ 
                         copystack(&ii,   input); 
                         copystack(&ss,   s); 
                         copystack(&oo,   output);
                        push(&oo,   pop(&ss));
                        stackseq(&ii,   &ss,   &oo);
                }
                push(s,pop(input));     /*再输入一个元素*/
                stackseq(input,   s,   output);
        }
}
void main()  
{
 int   i,n;
  stack input,s,output;
   initstack(&input,20);
    initstack(&s,20);
    initstack(&output,20);
 printf("Input n:\n");
 scanf("%d",&n);
  for(i=n;i> 0;i--)  
   push(&input,i);
 stackseq(&input,&s,&output);
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值