1. 程式人生 > >出棧序列的遍歷

出棧序列的遍歷

                                                                       怎麼樣把所有的可能的出棧順序輸出的

          在網上查找了很多關於怎麼樣把所有的可能的出棧順序輸出的的文章,不過遺憾的是,大部分的文章都是隻是說這個是卡特藍數,然後給出一個公式而這個往往只是一個可以求出有多少種可能的公式,網上的文章更加傾向於討論什麼問題適用卡特藍數。頂多就是看到下面的程式碼:
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

void func(vector<char>kind, int count[], int n)
{
if (count[0] >= 1)
{
kind.push_back('(');
count[0]--;
func(kind, count, n);
count[0]++;
kind.pop_back();
}
if ((count[1] >= 1) && (count[1] > count[0]))
{
kind.push_back(')');
count[1]--;
func(kind, count, n);
count[1]++;
kind.pop_back();
}
if (kind.size() == 2 * n)
{
vector<char>::iterator iter;
for (iter = kind.begin(); iter != kind.end(); iter++)
{
cout << (*iter) << " ";
}
cout << endl;

}
}
int main()
{

int n;
cout << "please input the number of ():" << endl;
cin >> n;
int count[2] = { n - 1,n };
vector<char>kind;
kind.push_back('(');
func(kind, count, n);
return 0;
}


我想你肯定第一次看到這個東西肯定是一頭霧水吧!我也是。不過我現在懂了我在這裡和大家分享一下吧。 1.問題的模型          在這裡我們假設出棧代表數字‘0’,入棧代表數字‘1’。我們的問題就可以轉換成求‘0’‘1’的組合序列有多少種了。那麼是不是‘0’,‘1’可以任意組合呢?答案肯定是no。 這個‘0’,‘1’的組合必須滿足卡特蘭數的規則: 1. 在‘0’的前面的序列‘1’的個數必須大於‘0’的個數(也就是說類似100這種序列是不可能的)。為什麼?因為‘1’代表入棧,‘0’代表出棧。入棧的次數必須大於出棧的次數你才可以繼續出棧啊…..這個應該沒什麼問題吧。 2. ‘0’和‘1’的個數是有限的。比如說你要求4個數的出棧入棧序列。那麼你就只有4個‘1’和4個‘0’,所以像“11111111”這種序列是不可能的雖然滿足第一點的要求。
ok,問題的實質已經清楚那麼來看看怎麼解決這個問題吧。 2.問題的求解(非遞迴哦) 你看到前面的別人的實現程式碼是否在心中已經瑟瑟發抖了啊(哈哈)。一看,怎麼是遞迴啊我完全懂不了啊,其實很多的遞迴的實現都是可以用非遞迴實現的(個人認為是所有的)。這裡我們來說一下非遞迴的求解思路吧。 我們可以很形象的把這個問題轉變成你要求1個數的出棧序列就是有倆個坑讓你用數字’0’,和‘1’按照我前面說的規則來填。2個數就是填4個坑,3個數就是填6個坑。怎麼樣好玩吧。 現在我們來開始填坑了。 我們只要思考這個坑填什麼,然後填完以後,繼續填下一個直到所有的坑填完 填坑的時候會出現三種情況 1. 只能填數字‘0’
2. 只能填數字‘1’ 3. 數字 ’0‘ 和 ‘1’都可以填寫。 那麼我們的求解思路就是:只能填’1‘的就只填‘1‘,只能填’0‘的就只填’0‘,然後 ’0‘和 ‘1‘都可以填寫的就先填一個’1‘,把這個位置“記”下來(也就是放入棧中注意必須是棧這種資料結果啊其中的原因就是你用其他的資料結構很難避免重複不相信你可以用佇列試一試),然後等所有的坑填完以後,重新返回將其填成0.再繼續把坑填完。當棧中的元素沒有元素了那麼所有的序列也就輸出來了。(這裡請讀者多思考幾遍這裡是核心 3.原始碼壓軸出場 其實我個人認為貼出原始碼並無意義,不過沒原始碼有的人就會說:自己做出來了嗎?自己都沒做出來在這裡瞎bb,好吧我無語了。所有還是貼一下原始碼來壓軸吧。當然這只不過是我的實現方法讀者可以自己思考的實現方法。ps:我的原始碼是用‘<’代表1,‘>’代表0
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include <stack>
using namespace std;
//這裡以括號的匹配來說明出棧序列的輸出,因為這兩個問題實質都是一樣的
int c = 0;
void function(int number)
{
vector<char> v; //問題就是有多少種滿足條件的序列。
v.push_back('<');//第一個元素看到是<這個是肯定的。
int count[2] = { number - 1,number }; //cout表示還有幾個<和>需要添進去。
stack<int> s; //用s來記錄有兩種情況的坑。
loop:
while (v.size() < 2*number)
{
if (count[0] > 0)
{
v.push_back('<');
if (count[1] > count[0])
s.push(v.size() - 1);
count[0]--;
}
else if(count[1] > 0)
{
v.push_back('>');
count[1]--;
}
}
for (auto x : v)
{
cout << x;
}
c += 1;
cout << c;
cout << endl;
if (!s.empty())
{
int n = s.top(); //n是下標
s.pop();
for (size_t i = 2*number-1; i >= n; i--)
{
if (v[i] == '<')
{
count[0]++;
}
else
{
count[1]++;
}
v.pop_back();
}
v.push_back('>');
count[1]--;
goto loop; 
}
}
int main()
{
cout << "請你輸入個數 :" << endl;
int n;
cin >> n;
function(n);
return 0;
}