題目描述
已知一個入棧序列,試求出所有可能的出棧序列數目。例如入棧序列為1,2,3,則可能的出棧序列有5種:1 2 3,1 3 2 ,2 1 3,2 3 1,3 2 1。
分析
要求解出棧序列的數目,還算比較容易的。已經有很多文章分析過這個問題,最終答案就是卡特蘭數,也就是說n個元素的出棧序列的總數目=C(2n, n) - C(2n, n-1) = C(2n, n) / (n+1)。在博文Catalan數 中提供了好幾種求解卡特蘭數的方法。
如果不分析求解的通項公式,是否可以寫程式求出出棧的序列數目呢?答案是肯定的,下面的一個程式可以求解出棧序列的數目,代碼來自網路中某一篇部落格,現在記不起出處了,所以不能標明,請原作者見諒。
#include <stdio.h>/* sum作為全域變數記錄共可能多少種情況*/int sum = 0;/* * 描述:遞迴計算共可能出現的出棧序列,無傳回值 * 參數: * in -- 目前存放於棧中的元素個數 * wait -- 目前還未進棧的元素個數 * out -- 目前已經出棧的元素個數 * num -- 一共有多少個元素 * */void f(int in, int wait, int out, int num){ /* 如果全部元素都出棧,表明有了一種新情況,總數加一*/ if (out == num) sum++; /* 否則繼續遞迴衍生新的狀態*/ else { /* 衍生方法1:讓一個元素進棧*/ if (wait > 0) f(in+1, wait-1, out, num); /* 衍生方法2:讓一個元素出棧*/ if (in > 0) f(in-1, wait, out+1, num); }}
/* 用main函數調用*/int main(){ /* 一共有n個元素*/ //int n = 5; int n; scanf("%d", &n); /* 剛開始時棧中有0個元素,有n個元素等待,有0個元素出了棧,共有n個元素*/ f(0, n, 0, n); printf ("%d\n", sum); return 0;}
擴充
上面只是求所有的出棧數目,如果要求所有的出棧序列呢?比如給定入棧序列為1 2 3,要求所有出棧序列。以下內容轉自http://blog.csdn.net/lzshlzsh/article/details/5910682
如所示:在每個節點可能有兩種操作:進棧,出棧。進棧則轉入左子樹,出棧則進入右子樹。當“未處理”元素為空白時,輸出序列就已經確定(中綠色節點所示)。注意在回退時需要維護輸出序列和棧的狀態。
#include <iostream> #include <vector> #include <iomanip> using namespace std; void func(int A[], int j, int n, vector<int> &stk, vector<int> &que) { static int cnt = 0; if (j >= n){ cout << ++cnt << ": "; for (unsigned int k = 0; k < que.size(); k++){ //列印出棧序列 cout << setw(5) << que[k]; } for (int k = stk.size() - 1; k >= 0; k--){ //列印棧中序列,注意這裡是從後往前列印 cout << setw(5) << stk[k]; } cout << endl; return; } stk.push_back(A[j]); /*入棧*/ func(A, j + 1, n, stk, que); /*左子樹*/ stk.pop_back(); /*退回到當前結點*/ if (!stk.empty()){ /*出棧*/ que.push_back(stk.back()); stk.pop_back(); func(A, j, n, stk, que); /*右子樹*/ stk.push_back(que[que.size() - 1]); que.pop_back(); } } int main() { int A[] = {1, 2, 3}; vector<int> stk; vector<int> que; func(A, 0, sizeof(A) / sizeof(int), stk, que); return 0; }