1. 程式人生 > >給定入棧順序,輸出所有可能出棧情況及所有情況的總數

給定入棧順序,輸出所有可能出棧情況及所有情況的總數

一個長度為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. }