給定入棧順序,輸出所有可能出棧情況及所有情況的總數
一個長度為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只能看成一個整體。
這樣就可以用遞迴的方式求解,虛擬碼如下:
-
dostack(輸入佇列,中間棧,輸出佇列)
-
if(輸入佇列為空)
-
if(中間棧為空)
-
輸出輸出佇列中的結果
-
else
-
中間棧出棧,放入輸出佇列
-
dostack(輸入佇列,中間棧,輸出佇列)
-
else
-
if(中間棧非空)
-
新建輸入佇列2、中間棧2、輸出佇列2
-
中間棧2出棧並放入輸出佇列2
-
dostack(輸入佇列2,中間棧2,輸出佇列2)
-
輸入隊列出隊一個數並壓入中間棧
-
dostack(輸入佇列,中間棧,輸出佇列)
其基本思想為對於中間棧的每一個時刻拍照,都遞迴其後續的所有可能,由於在遞迴返回的時候還需要遞迴前的資訊,所以每次遞迴都是新建資料結構而儲存當前時刻的狀態。若輸入佇列已經為空,則中間棧只有一種出棧方式,中間棧也為空時遞迴結束。
詳細程式碼如下:
輸入為序列的長度n,初始化序列為1,2,3…n,而輸出則為所有可能的出棧數列。
-
//輸入壓棧順序如1 2 3 4 5 6 7 8 ..n,確定所有可能出棧的得到的結果
-
//同時計算情況的總數n
-
#include <stdio.h>
-
#include <iostream>
-
#include <stack>
-
#include <queue>
-
using namespace std;
-
//遞迴法只計算所有情況總數
-
int getPermuStack(int n, int m)
-
{
-
if(n == 0)//遞迴邊界
-
return 1;
-
if(m == 0)//(n,0)問題的處理
-
return getPermuStack(n-1, 1);
-
return getPermuStack(n, m-1) + getPermuStack(n-1, m+1);
-
}
-
//Catalan公式法 最多隻能算到n=10
-
long long jiecheng(long long n)
-
{
-
if(n==1) return 1;
-
else return n*jiecheng(n-1);
-
}
-
long long catalan(long long n)
-
{
-
return (jiecheng(2*n)/jiecheng(n+1)/jiecheng(n));
-
}
-
//下面演算法函式既輸出所有可能壓棧(不全壓,但仍按給定順序壓棧)的情況,也輸出對應的出棧情況及總數
-
int n,i,j;
-
int res;
-
stack <int> s;
-
queue <int> in,out;
-
void clear(stack <int> &s)
-
{
-
while(!s.empty())
-
s.pop();
-
}
-
void clear(queue <int> &s)
-
{
-
while(!s.empty())
-
s.pop();
-
}
-
void print(queue <int> i)
-
{
-
while(!i.empty())
-
{
-
cout<<i.front();
-
i.pop();
-
}
-
cout<<endl;
-
}
-
void dostack(queue <int> in,stack <int> s,queue <int> out)
-
{
-
if(in.empty())
-
{
-
if(s.empty())
-
{
-
res++;
-
print(out);
-
}
-
else
-
{
-
out.push(s.top());
-
s.pop();
-
dostack(in,s,out);
-
}
-
}
-
else
-
{
-
if(!s.empty())
-
{
-
stack <int> ts;
-
queue <int> tin,tout;
-
tin=in;
-
ts=s;
-
tout=out;
-
tout.push(ts.top());
-
ts.pop();
-
dostack(tin,ts,tout);
-
}
-
s.push(in.front());
-
in.pop();
-
dostack(in,s,out);
-
}
-
}
-
int main()
-
{
-
cout<<"請輸入1~n共n個數:";
-
while(cin>>n)
-
{
-
res=0;
-
clear(in);
-
clear(out);
-
clear(s);
-
for(i=n;i>=1;i--)
-
in.push(i);
-
dostack(in,s,out);
-
cout<<"對應的出棧情況總數="<<res<<endl;
-
}
-
cout<<"1~n依次進棧時,使用遞迴函式所有的情況總數:"<<endl;
-
for(i=1;i<15;i++)
-
cout<<"n="<<i<<" "<<getPermuStack(i,0)<<endl;
-
cout<<endl<<"1~n依次進棧時,使用Catalan公式所有的情況總數:"<<endl;
-
for(i=1;i<15;i++)
-
cout<<"n="<<i<<" "<<catalan(i)<<endl;
-
return 0;
-
}