使用递归对方案进行排列

Lit*_*tle 3 scheme

我发现以下代码在Scheme中进行了排列。我的意思是,如果我输入类似参数'(1 2 3),它将给我:

((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))
Run Code Online (Sandbox Code Playgroud)

代码如下:

(define (remove x lst)
  (cond
    ((null? lst) '())
    ((= x (car lst))(remove x (cdr lst)))
    (else (cons (car lst) (remove x (cdr lst))))))

(define (permute lst)
  (cond
    ((= (length lst) 1)(list lst))
    (else (apply append(map(lambda (i) (map (lambda (j)(cons i j))
                                            (permute (remove i lst))))lst)))))
Run Code Online (Sandbox Code Playgroud)

第一个函数remove看起来很简单,那就是通过将x与列表的开头进行比较,并与其余部分进行递归调用,从而摆脱x表示的角色,即使它重复与否。

我完全不了解的部分是置换功能。对于我所知道的,map将函数应用于参数的每个元素(在本例中为列表),而对一个参数完全只应用一次函数。那么这行到底是做什么的:

(apply append(map(lambda (i) (map (lambda (j)(cons i j))
                                                (permute (remove i lst))))lst)))))
Run Code Online (Sandbox Code Playgroud)

对我来说,似乎只想创建一个包含两个元素的对:i和j,它们将成为排列了元素的列表(如果我们假设列表只是一堆串联的对)。但是再次调用用i进行置换和清除的部分,该部分在做什么?只是删除列表的头以生成具有固定该对的头的元素i的列表子集,直到用完元素了吗?

有什么帮助吗?

谢谢

Fre*_*Foo 5

让我们从内到外进行区分。修复lst内部表达式并将其应用于其元素之一。

> (define lst '(1 2 3))
> (define i 1)
> (permute (remove i lst))
((2 3) (3 2))
Run Code Online (Sandbox Code Playgroud)

看起来不错:内部表达式删除和元素并递归地生成列表其余部分的排列。现在maplambda这些排列如下:

> (map (lambda (j) (cons i j)) (permute (remove i lst)))
((1 2 3) (1 3 2))
Run Code Online (Sandbox Code Playgroud)

因此,内部map会产生所有以some开头的排列,i我们已将其设置为1此处。

外层map通过将的所有元素lst视为第一个元素来确保生成所有排列。

> (map (lambda (i) (map (lambda (j) (cons i j))
>                       (permute (remove i lst))))
>      lst)
(((1 2 3) (1 3 2)) ((2 1 3) (2 3 1)) ((3 1 2) (3 2 1)))
Run Code Online (Sandbox Code Playgroud)

但这会产生太多嵌套的列表。应用展append平列表列表,

> (append '(1 2) '(3 4) '(5 6))
(1 2 3 4 5 6)
> (apply append '((1 2) (3 4) (5 6)))
(1 2 3 4 5 6)
Run Code Online (Sandbox Code Playgroud)

因此我们得到了排列的平面清单。