给定入栈顺序,输出所有可能出栈情况及所有情况的总数

一个长度为n的无重复序列入栈的所有出栈方式

例如1、2、3这三个数字,入栈并出栈共有5种方式,分别为:321、312、231、213、123。那么对于长度为n的无重复序列中所有的出栈方式有哪些呢?

为了设计计算的算法,我们可以用队列(queue)来模拟输入,队列的输出则按照原先序列的顺序。使用一个栈(stack)来模拟入栈和出栈,结果保存在另外一个队列(queue)中。

现在的问题来了,怎么样可以实现所有的出栈入栈操作。首先来看看出栈和入栈是怎么回事,对于123这个序列,1先入栈之后有两种选择,1出栈和2入栈,而若2已经入栈之后,在2出栈之前1则不能先行出栈,故对于1我们只需要考虑其在2入栈之前出栈的情况,若1在栈内时2入栈,则1与2只能看成一个整体。

这样就可以用递归的方式求解,伪代码如下:

 
  1. dostack(输入队列,中间栈,输出队列)

  2.  
  3. if(输入队列为空)

  4.  
  5. if(中间栈为空)

  6.  
  7. 输出输出队列中的结果

  8.  
  9. else

  10.  
  11. 中间栈出栈,放入输出队列

  12.  
  13. dostack(输入队列,中间栈,输出队列)

  14.  
  15. else

  16.  
  17. if(中间栈非空)

  18.  
  19. 新建输入队列2、中间栈2、输出队列2

  20.  
  21. 中间栈2出栈并放入输出队列2

  22.  
  23. dostack(输入队列2,中间栈2,输出队列2)

  24.  
  25. 输入队列出队一个数并压入中间栈

  26.  
  27. dostack(输入队列,中间栈,输出队列)

其基本思想为对于中间栈的每一个时刻拍照,都递归其后续的所有可能,由于在递归返回的时候还需要递归前的信息,所以每次递归都是新建数据结构而保存当前时刻的状态。若输入队列已经为空,则中间栈只有一种出栈方式,中间栈也为空时递归结束。

详细代码如下:

输入为序列的长度n,初始化序列为1,2,3…n,而输出则为所有可能的出栈数列。

 
  1. //输入压栈顺序如1 2 3 4 5 6 7 8 ..n,确定所有可能出栈的得到的结果

  2. //同时计算情况的总数n

  3. #include <stdio.h>

  4. #include <iostream>

  5. #include <stack>

  6. #include <queue>

  7.  
  8. using namespace std;

  9. //递归法只计算所有情况总数

  10. int getPermuStack(int n, int m)

  11. {

  12. if(n == 0)//递归边界

  13. return 1;

  14. if(m == 0)//(n,0)问题的处理

  15. return getPermuStack(n-1, 1);

  16. return getPermuStack(n, m-1) + getPermuStack(n-1, m+1);

  17. }

  18. //Catalan公式法 最多只能算到n=10

  19. long long jiecheng(long long n)

  20. {

  21. if(n==1) return 1;

  22. else return n*jiecheng(n-1);

  23. }

  24. long long catalan(long long n)

  25. {

  26. return (jiecheng(2*n)/jiecheng(n+1)/jiecheng(n));

  27. }

  28. //下面算法函数既输出所有可能压栈(不全压,但仍按给定顺序压栈)的情况,也输出对应的出栈情况及总数

  29. int n,i,j;

  30. int res;

  31. stack <int> s;

  32. queue <int> in,out;

  33. void clear(stack <int> &s)

  34. {

  35. while(!s.empty())

  36. s.pop();

  37. }

  38. void clear(queue <int> &s)

  39. {

  40. while(!s.empty())

  41. s.pop();

  42. }

  43. void print(queue <int> i)

  44. {

  45. while(!i.empty())

  46. {

  47. cout<<i.front();

  48. i.pop();

  49. }

  50. cout<<endl;

  51. }

  52. void dostack(queue <int> in,stack <int> s,queue <int> out)

  53. {

  54. if(in.empty())

  55. {

  56. if(s.empty())

  57. {

  58. res++;

  59. print(out);

  60. }

  61. else

  62. {

  63. out.push(s.top());

  64. s.pop();

  65. dostack(in,s,out);

  66. }

  67. }

  68. else

  69. {

  70. if(!s.empty())

  71. {

  72. stack <int> ts;

  73. queue <int> tin,tout;

  74. tin=in;

  75. ts=s;

  76. tout=out;

  77. tout.push(ts.top());

  78. ts.pop();

  79. dostack(tin,ts,tout);

  80. }

  81. s.push(in.front());

  82. in.pop();

  83. dostack(in,s,out);

  84. }

  85. }

  86. int main()

  87. {

  88. cout<<"请输入1~n共n个数:";

  89. while(cin>>n)

  90. {

  91. res=0;

  92. clear(in);

  93. clear(out);

  94. clear(s);

  95. for(i=n;i>=1;i--)

  96. in.push(i);

  97. dostack(in,s,out);

  98. cout<<"对应的出栈情况总数="<<res<<endl;

  99.  
  100. }

  101. cout<<"1~n依次进栈时,使用递归函数所有的情况总数:"<<endl;

  102. for(i=1;i<15;i++)

  103. cout<<"n="<<i<<" "<<getPermuStack(i,0)<<endl;

  104.  
  105. cout<<endl<<"1~n依次进栈时,使用Catalan公式所有的情况总数:"<<endl;

  106. for(i=1;i<15;i++)

  107. cout<<"n="<<i<<" "<<catalan(i)<<endl;

  108.  
  109.  
  110. return 0;

  111. }

猜你喜欢

转载自blog.csdn.net/u010112268/article/details/83793422
今日推荐