使用单个堆栈生成排列

发布于 2024-11-17 10:21:30 字数 130 浏览 5 评论 0原文

任何人都可以解释一下在仅使用单个堆栈时生成可能的排列的算法,并且推入和弹出是唯一允许的操作。 查了很多资料,但没有明确的答案。 这种排列的总数也由加泰罗尼亚数字给出。但我没能得到这方面的证据。如果可能的话,也请解释一下。

谢谢!!

Can anyone please explain algorithm to generate the permutations possible when using only a single stack and push and pop are the only operations allowed.
Have searched about it a lot, but no definite answer.
Also the total number of such permutations is given by catalan numbers. But I fail to get a proof for that. Kindly explain that as well if possible.

Thanks!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

櫻之舞 2024-11-24 10:21:30

该问题使用输入队列和输出队列以及堆栈。

这些操作是“将一个项目从输入队列推入堆栈”和“将一个项目从堆栈弹出到输出队列”。

                  1 2 3
output  ______   ______  input  
              \ /
        <--+   |   +---
       pop |   |   | push
           |   |   v

             stack

例如,对于输入 1 2 3,您可以按照以下顺序获取输出 2 1 3

  • 将 1 从输入推入堆栈
  • 将 2 从输入推入堆栈
  • 弹出2 从堆栈到输出
  • pop 1 从堆栈到输出
  • 入栈 3 从输入到堆栈
  • pop 3 从堆栈到输出

但是,如果您尝试生成 3 1 2,您将遇到困难。


如何生成这些操作可能的所有排列?嗯,递归地做起来很简单:在任何给定的状态(其中“状态”由输入队列、堆栈和输出队列的内容组成)中,最多有两个可以执行的可能操作(您可以推送如果输入队列上至少有一项;如果堆栈上至少有一项,则可以弹出),这将为您提供最多两种可能的新状态供您探索。

有关此问题以及与加泰罗尼亚数字的关系的更多详细信息,请查找 Knuth 的“计算机编程艺术”,第 1 卷(第 3 版)的副本 - 在第 2.2.1 节中进行了讨论;请参阅第 242-243 页上的练习 2 - 5(以及第 240 页上我的图表的更好版本!)。

This problem uses an input queue and an output queue as well as a stack.

The operations are "push an item from the input queue onto the stack" and "pop an item from the stack onto the output queue".

                  1 2 3
output  ______   ______  input  
              \ /
        <--+   |   +---
       pop |   |   | push
           |   |   v

             stack

For example, with the input 1 2 3, you can get the output 2 1 3 with the following sequence:

  • push 1 from input to stack
  • push 2 from input to stack
  • pop 2 from stack to output
  • pop 1 from stack to output
  • push 3 from input to stack
  • pop 3 from stack to output

But you'll have a hard time if you try to generate 3 1 2.


How do you generate all the permutations that are possible with these operations? Well, it's trivial to do recursively: in any given state (where the "state" consists of the contents of the input queue, the stack, and the output queue), there are at most two possible operations you can perform (you can push if there is at least one item on the input queue; you can pop if there is at least one item on the stack), which will give you at most two possible new states to explore.

For further detail regarding this problem, and the relationship with Catalan numbers, go and find a copy of Knuth's "The Art of Computer Programming", volume 1 (3rd ed.) - it's discussed in §2.2.1; see exercises 2 - 5 on pp. 242-243 (and a better version of my diagram on p. 240!).

巡山小妖精 2024-11-24 10:21:30

首先,在以下假设下,不可能编写一个算法来对任意排列执行此操作:

  1. 您只能按顺序从输入中读取。

  2. 写入输出同样是顺序发生的,写入输出的数据一旦写入就无法读取。

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

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

Wiki: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

或者如果您修复排列,问题就会变得有限,并且您同样不需要堆栈。您只需将常用算法展开到所有输入的特殊情况(即就像在编译器中进行部分评估一样)。这是非常可怕的,所以我不会费心写出所有细节,但它仍然有效,因为可能的输入总数是一个固定的(但很大!)常量。

First, it is impossible to write an algorithm to do this for an arbitrary permutation under the following assumptions:

  1. You can only read from the input sequentially.

  2. Writing the output similarly occurs sequentially, and the data written to the output can not be read once written.

  3. In addition to the one stack, you are allowed only a constant amount of memory. (This means no additional recursion or data structures).

This is a consequence of the pumping lemma for context free languages:

Wiki: http://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages

(Or also check: Michael Sipser (1997). Introduction to the Theory of Computation. I believe this is one of the exercises in chapter 4.)

Now you can easily implement an algorithm which fixes this problem by breaking any one of these assumptions. For example, if you can read from the input arbitrarily, then you don't need a stack:

def permute(seq, permutation):
    result = []
    for i in permutation:
        result.push(seq[i])
    return result

Or if you fix a permutation, the problem becomes finite and you similarly don't need a stack. You just unfold the usual algorithm to special case over all inputs (ie just like doing partial evaluation in a compiler). This is pretty horrible, so I won't bother writing out all the details, but it still works due to the fact the total number of possible inputs is a fixed (but large!) constant.

国粹 2024-11-24 10:21:30

我正在考虑同样的问题,最终编写了一个小的 Prolog 程序来生成排列,并“发现”了与加泰罗尼亚数字的关系,然后找到了你的问题。所以这并不是你问题的真正答案,但这里是 Prolog 程序:

% 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

I was thinking about the same problem and ended up writing a small Prolog program to generate the permutations, and "discovered" the relation to Catalan numbers, and then found your question. So this is not really an answer to your question but here is the Prolog program:

% 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).

Proof that not all the n! permutations are possible:

?- findall(Seq, pushpop(3, Seq), Seqs).
Seqs = [[3, 2, 1], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]].

Proof that it generates Catalan numbers (or this would be a proof if it wasn't for the stack overflow ;)):

?- 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文