如何在Scheme中重复生成一定大小的所有排列?

时间:2010-07-05 13:40:35

标签: scheme permutation

我正在学习Scheme,我正在尝试以一定的大小重复生成排列。

例如,给定n = 4并设置S = {a,b,c,d,e,f},我想生成所有可能的排列:{a,a,a,a},{a中,a,A,b},...,{A,A,A,F},{A,A,b,A},{A,A,b,b},...,{A,A ,b,F},... {F,A,A,A},{F,A,A,b} ...,{F,A,A,F},... {F,F, F,F}。

麻烦的是,我无法理解如何选择'a'4次,并记住我已经选择了4次,然后选择'a'3次,'b'一次,并记住这一切,所以我不再选择了。

我知道这些问题最好通过递归算法来解决,但它只会使一切变得更复杂,例如,我如何记住递归,我选择了哪些元素。

我根本不知道如何解决这个问题。如果有人写出解决这个问题的思考过程,我会很高兴。我非常感激!

请帮帮我。

谢谢,Boda Cydo。

3 个答案:

答案 0 :(得分:4)

从程序的界面和预期结果开始是很好的。您的程序将被称为(permutations size elements),并且应该返回ELEMENTS中项目的排列列表,每个排列长度为SIZE项目。如图所示,您将以列表形式表示“排列”。因此,如果您拨打(permutations 1 '(a b c)),则预计输出为((a) (b) (c))

所以关于递归过程的技巧,你必须弄清楚你可以轻松回答的基本条件是什么,以及你可以通过修改更简单问题的解决方案来回答的递归步骤。对于PERMUTATIONS,计算递归步骤将涉及减小SIZE,因此基本步骤将是当SIZE为0时,并且答案是零长度置换的列表,即。即(())

要回答递归步骤,你必须弄清楚如何处理大小为N-1的结果以获得大小为N的结果。为此,它可以帮助写出小N的一些预期结果看看你是否能辨别出一种模式:

ELEMENTS = (a b)
SIZE   (PERMUTATIONS SIZE ELEMENTS)
0      ( () )
1      ( (a) (b) )
2      ( (a a) (a b) (b a) (b b) )
3      ( (a a a) (a a b) (a b a) (a b b) (b a a) ... )

所以基本上你要做的是,给定R = (permutations n elements),你可以通过在R中取每个排列P得到(permutations (+ n 1) elements),然后对于ELEMENTS中的每个元素E,将E连接到P创建一个新的排列,并收集它们的列表。我们可以使用嵌套MAP执行此操作:

(define (permutations size elements)
  (if (zero? size)
      '(())
      (flatmap (lambda (p)            ; For each permutation we already have:
                 (map (lambda (e)     ;   For each element in the set:
                        (cons e p))   ;     Add the element to the perm'n.
                      elements))
               (permutations (- size 1) elements))))

我正在使用FLATMAP进行外部映射,因为内部MAP会创建新排列的列表,我们必须将这些列表附加在一起,以创建我们想要的一个大的排列列表。

当然,这都是假设你知道并且很好地处理像MAP这样的序列操作。如果你不这样做,那就像我刚刚在这里做出的优雅解决方案一样真的很难。

答案 1 :(得分:1)

这是另一个版本:我使用的是reduce,而不是flatmap。我是在MIT-scheme写的。

(define (per s)

  (define (ins c before after)
    (if (null? after)
        (list (append before (list c)))
        (append (list (append before (list c) after))
                (ins c
                     (append before (list (car after)))
                     (cdr after)))))
  (define (iter l)
    (cond ((null? l)
           '(()))
          (else
           (let ((rest (iter (cdr l))))
             (reduce-left append
                          ()
                          (map (lambda (x) (ins (car l) () x) )
                               rest))))))
  (iter s))

(per '(1 3 2 4))

答案 2 :(得分:0)

提示:您可以使用参数进行递归调用以“记住”其他递归调用已完成的操作。 ;)