请问有人能够解释一下使用单个栈且只允许push和pop操作时,如何生成可能的排列算法?我已经搜索了很多,但没有明确的答案。此外,这样排列的总数由卡特兰数给出。但我无法证明这一点。如果可能的话,请详细解释。
谢谢!
请问有人能够解释一下使用单个栈且只允许push和pop操作时,如何生成可能的排列算法?我已经搜索了很多,但没有明确的答案。此外,这样排列的总数由卡特兰数给出。但我无法证明这一点。如果可能的话,请详细解释。
谢谢!
1 2 3
output ______ ______ input
\ /
<--+ | +---
pop | | | push
| | v
stack
1 2 3
,您可以通过以下序列获得输出2 1 3
:
3 1 2
,可能会很困难。首先,在以下假设下,不可能编写一个算法来对任意排列进行操作:
只能按顺序从输入中读取。
同样地,写入输出是按顺序进行的,并且一旦写入,就无法再读取写入到输出的数据。
除了一个栈外,您只允许使用恒定数量的内存。(这意味着不能使用额外的递归或数据结构)。
这是上下文无关语言泵引理的一种结果:
维基百科:http://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages
(或者也可以查看:Michael Sipser(1997年)。计算理论介绍。我相信这是第4章中的一个练习题。)
现在,您可以通过破坏其中任何一个假设来轻松实施解决此问题的算法。例如,如果您可以任意读取输入,则不需要使用堆栈:
def permute(seq, permutation):
result = []
for i in permutation:
result.push(seq[i])
return result
% Generate permutation counts
count_pushpop(N-K) :-
length(_, N),
findall(Seq, pushpop(N, Seq), Seqs),
length(Seqs, K).
% Create an integer sequence from 1 to N
% and permutate it using all possible push-pop
% operations starting with an empty stack.
pushpop(N, Seq) :-
numlist(1, N, List),
pushpop(List, [], Seq).
% Generate all the possible ways a list
% of items can be pushed into a stack
% and poped out of it.
pushpop([], [], []).
pushpop([H | List], Stack, Seq) :-
pushpop(List, [H | Stack], Seq).
pushpop(List, [H | Stack], [H | Seq]) :-
pushpop(List, Stack, Seq).
证明不是所有的 n!
种排列都是可能的:
?- findall(Seq, pushpop(3, Seq), Seqs).
Seqs = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]].
证明它生成卡特兰数(如果没有堆栈溢出,这将是一个证明;):
?- count_pushpop(N-K).
N = K, K = 0 ;
N = K, K = 1 ;
N = K, K = 2 ;
N = 3,
K = 5 ;
N = 4,
K = 14 ;
N = 5,
K = 42 ;
N = 6,
K = 132 ;
N = 7,
K = 429 ;
N = 8,
K = 1430 ;
N = 9,
K = 4862 ;
N = 10,
K = 16796 ;
N = 11,
K = 58786 ;
N = 12,
K = 208012 ;
ERROR: Out of global stack
n
的元素,您必须弹出并存储在某个地方堆栈顶部的n
个元素,从而创建了额外的O(n)
内存需求。我有什么遗漏吗? - AnT stands with Russia