A stack may be regarded as a railway switching network like the one in the figure.
Cars numbered 1, 2, …, n are on the line at the left, and it is desired to rearrange (permute) the cars as they leave on the right-hand track. A car that is on the spur (stack) can be left there or sent on its way down the right track, but it can never be sent back to the incoming track. For example, if n=3, and we have the cars 1,2,3 on the left track, then 3 first goes to the spur. We could then send 2 to the spur, then on its way to the right, then send 3 on the way, then 1, obtaining the new order 1,3,2.
For general n, find how many permutations can be obtained by using this stack. And output all the permutations by using the switching network in the figure.
分析
三条轨道相应记为left, down, right…显然用递归方法解决此问题很直观,易懂
为简化分析,假设left的数都要经过down,(即使left直接去到right也当成是先到down再到right),且数不能从down或right回到left
则有3种情况
- 当left中没有数时,此时数都已在down和right, 这种情况下,顺序已经确定,无法再更改顺序. 将right的数依次出栈输出, 然后再将down的数依次出栈输出
- 当down中没有数时,此时只能将left中的数出栈, 压到down中..
- 当不属于上述两种情况时,即left和down中都有数时,
此时有两中选择
1.)将left中的一个数出栈, 压down中
2.)left中的数不变, 将down中的一个数出栈,压到right中
很显然,left,只需在一端操作, 可以将其设计为stack;
同样,down也只需在一端操作,且具有先进先出特点, 适合设计为stack
而right需要在两端操作, 第1种情况时,需要在一端将数出栈输出, 而在第3种情况中,将从down中出来的数,要压到right的另一端, 故可将right设计为双端队列deque
由以上分析, 借助C++ STL中的模版类,很容易写出具体实现出来, 代码见文件train.cpp
所有排列输出到文件D:/output.txt
由于此问题所有的排列的总数是Catlan数, 由Catlan数计算公式,写了个函数验证一下上述递归方法解的个数是否正确..
关于catalan数,可见这篇文章
下面是n=4时的所有排列, 输出序列为从左到右
4 3 2 1 (4先出栈,1最后出栈)
4 3 1 2
4 2 3 1
4 2 1 3
4 1 2 3
3 4 2 1
3 4 1 2
3 2 4 1
3 2 1 4
3 1 2 4
2 3 4 1
2 3 1 4
2 1 3 4
1 2 3 4
Total number of all the permutations is 14
//
train.cpp
#include
<
iostream
>
#include
<
fstream
>
#include
<
stack
>
#include
<
queue
>
using
namespace
std;
int
counter
=
0
;
long
double
catalan(
int
n)
...
{
if(n==0) return 1;
else return (4*n-2)*catalan(n-1)/(n+1);
}
void
recur(stack
<
int
>
left, stack
<
int
>
down, deque
<
int
>
right, ofstream
&
fout)
...
{
int left_num=left.size();
int down_num=down.size();
if(left_num==0)
...{
while(!right.empty())
...{
cout<<right.front()<<" ";
fout<<right.front()<<" ";
right.pop_front();
}
while(!down.empty())...{
cout<<down.top()<<" ";
fout<<down.top()<<" ";
down.pop();
}
fout<<endl;
cout<<endl;
counter++;
return ;
}
else if(down_num==0)
...{
down.push(left.top());
left.pop();
recur(left, down, right, fout);
}
else ...{
int temp=down.top();
right.push_back(temp);
down.pop();
recur(left, down, right, fout);
right.pop_back();
down.push(temp);
down.push(left.top());
left.pop();
recur(left, down, right, fout);
}
return ;
}
int
main()
...
{
int num;
ofstream fout;
cout<<"Input a number: ";
while(cin>>num)
...{
fout.open("d:/permutations.txt");
counter=0;
stack<int> left;
stack<int> down;
deque<int> right;
int i=1;
while(i<=num)
...{
left.push(i);
i++;
}
recur(left, down, right, fout);
cout<<"Total number of all the permutations is "<<counter<<endl;
fout<<"Total number of all the permutations is "<<counter<<endl;
cout<<" Input a number: ";
fout.close();
}
return 0;
}