问题:
给定序列Si ,0<=i<n , 求该序列按顺序入栈时,所有合法的出栈序列
算法:
考虑使用回溯模拟这一操作过程,思路是,使用一个指针指向当前序列字符,准备一个栈,用来模拟入栈,准备一个队列,用来接收出栈元素,当指针指向字符末尾,也就是n时,说明所有字符都已经入栈完成,这是回溯结束,回溯结束时,栈和队列都有可能非空,栈非空时,将栈内元素弹出到队列末尾,然后依次出队得到出栈序列。
note:对于指针当前指向的字符,有两种可能的操作:1,将其入栈;2,不入栈,此时弹出栈顶元素到队列,此时完成出栈操作
实现:
程序
#include <iostream>
#include <stack>
#include <deque>
using namespace std;
//使用回溯法解决 每次入栈一个元素时,要么弹出,要么保持
stack<char> s1;
deque<char> q1;
int total = 0;
void backtracking(string str, int num)
{
if (num == str.size())
{
stack<char> s1tmp = s1;
deque<char> q1tmp = q1;
string tmp = "";
while (!s1.empty())
{
q1.push_back(s1.top()); s1.pop();
}
while (!q1.empty())
{
tmp.push_back(q1.front()); q1.pop_front();
}
total++;
cout << tmp << endl;
s1 = s1tmp;
q1 = q1tmp;
return;
}
//当前元素立即入栈
s1.push(str[num]);
backtracking(str, num + 1);
s1.pop();
//栈元素立即弹出
if (!s1.empty())
{
int tmp = s1.top();
q1.push_back(tmp); s1.pop();
backtracking(str, num );
s1.push(tmp);
q1.pop_back();
}
}
int main() {
string s = "abcde";
backtracking(s, 0);
cout << "共有:" << total << "种" << endl;
}
运行结果
分析
这个有一个公式可以直接求出出栈序列的个数,如下
n是序列长度,本文中n等于5,带入公式得42,验证了程序正确性。