Algorithm 使用单个堆栈生成置换

Algorithm 使用单个堆栈生成置换,algorithm,stack,permutation,catalan,Algorithm,Stack,Permutation,Catalan,有人能解释一下当只使用一个堆栈时生成排列的算法吗?push和pop是唯一允许的操作。 我找了很多,但没有确切的答案。 同样,这种排列的总数由加泰罗尼亚数给出。但我没能找到证据。如果可能的话,请解释一下 谢谢 此问题使用输入队列、输出队列以及堆栈 操作包括“将项目从输入队列推送到堆栈”和“将项目从堆栈弹出到输出队列” 123 输出输入 \ / 首先,在以下假设下,不可能为任意排列编写这样的算法: 只能按顺序读取输入 写入输出类似地按顺序进行,写入输出的数据一经写入就无法读取 除了一个堆栈之外,只允

有人能解释一下当只使用一个堆栈时生成排列的算法吗?push和pop是唯一允许的操作。 我找了很多,但没有确切的答案。 同样,这种排列的总数由加泰罗尼亚数给出。但我没能找到证据。如果可能的话,请解释一下


谢谢

此问题使用输入队列、输出队列以及堆栈

操作包括“将项目从输入队列推送到堆栈”和“将项目从堆栈弹出到输出队列”

123
输出输入
\ /

首先,在以下假设下,不可能为任意排列编写这样的算法:

  • 只能按顺序读取输入

  • 写入输出类似地按顺序进行,写入输出的数据一经写入就无法读取

  • 除了一个堆栈之外,只允许使用恒定的内存量。(这意味着没有额外的递归或数据结构)

  • 这是上下文无关语言的泵引理的结果:

    维基:

    (也可以查阅: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]].
    
    它生成加泰罗尼亚数字的证据(如果不是堆栈溢出,这将是一个证据;):


    我不理解“单堆栈”的要求。如果我使用一个附加的数据结构,它不是一个“堆栈”,而是一个“数组”或“队列”或“列表”,该怎么办。这样行吗?我想那是不允许的。但在这种情况下,我不明白这怎么可能。为了在堆栈中的深度
    n
    处检索元素,必须弹出并存储位于其顶部的
    n
    元素,从而需要额外的
    O(n)
    内存。我遗漏了什么吗?另外,可能可以使用语言级递归实现它,这意味着第二个堆栈将隐式地作为嵌套函数调用的本地上下文的“堆栈”出现。这允许吗?我猜这是关于递归的奇怪作业?编辑哈哈,奥黛丽,你在我做同样的事情时把它打出来了。这个排列应该如何表示?它是在运行时固定的还是动态指定的?应该如何处理输出?它是一个接一个地发送到只读输出队列中,还是仅仅存储在堆栈中?另外,如何指定输入?是否再次将其预加载到堆栈上?允许多少暂存内存?单堆栈的意思是只允许push和poop操作。输入是以队列的形式出现的,如1、2、3、4、5,一旦元素被弹出,它就会被发送到输出队列,并且不能被推回。
    ?- 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