我找到了以下代码,它在Scheme中进行了排列。我的意思是如果我输入相似的参数'(1 2 3)它会给我:
((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1))
代码如下:
(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)))))
第一个函数删除,似乎很简单,只有通过将它与列表的开头进行比较并以其他方式递归调用,才能除去x表示的字符,即使它是否重复。
我完全没有得到它的部分是置换功能。对于我所知道的地图,将一个函数应用于参数的每个元素(在本例中为一个列表),并且apply只将一个函数完全应用于所有参数。那么这一行到底是做什么的:
(apply append(map(lambda (i) (map (lambda (j)(cons i j))
(permute (remove i lst))))lst)))))
对我而言,它似乎只是想创建一个包含两个元素的对:i和j,它们将成为列表中的元素置换(如果我们假设列表只是一堆连接对) 。但那个再次呼唤置换和删除的部分,那个部分在做什么?只是删除列表的头部以生成列表的子集,其中元素i的头部是固定的,直到元素用尽为止?
任何帮助?
由于
答案 0 :(得分:5)
让我们分开,从内到外。修复lst
并将内部表达式应用于其中一个元素。
> (define lst '(1 2 3))
> (define i 1)
> (permute (remove i lst))
((2 3) (3 2))
看起来很好:内部表达式删除了元素,并以递归方式生成列表其余部分的排列。现在map
lambda
超过这些排列:
> (map (lambda (j) (cons i j)) (permute (remove i lst)))
((1 2 3) (1 3 2))
因此,内部map
会生成以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)))
但这会生成嵌套太多的列表。应用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)
所以我们得到一个排列的平面列表。
答案 1 :(得分:2)
我总是发现更容易理解更高的算法 在深入实施并尝试理解之前的水平 发生了什么事。所以问题是:排列是什么 列表,你会怎么找到它们?
单个元素列表的排列显然只是列表 本身。
(a b)
的排列是集合[(a b) (b a)]
。
(a b c)
的排列是集合
[(a b c) (a c b) (b c a) (b a c) (c a b) (c b a)]
一般来说有n!长度列表n的排列 - 我们有n 第一个元素的选择,一旦我们选择了(n-1)个选项 对于第二个元素,(n-2)表示第三个元素,依此类推。这个 随着我们越来越多地修复第一个,自由度会降低 列表中的元素非常具有启发性:也许我们可以代表 找到长度为n的列表的排列 长度列表的排列(n - 1),依此类推,直到达到 单元素列表的排列。
事实证明,列表的排列恰好是集合 [元素前置于list \ element的排列,为每个元素 列表中的元素]。
查看(a b c)
案例证实了这一点
是的 - 我们a
前面有(b c)
和(c b)
在(b c)
和b
之前(a c)
,(c a)
的排列等等。这个
将元素添加到子列表的操作可以定义为
(define (prepend j)
(cons element j))
以及为所有人做的操作
子列表的排列将为(map prepend (permute
sublist))
。现在,为每个元素定义一个新的prepend函数是
也许是矫枉过正 - 特别是因为它们都有相同的形式。那么一个
更好的方法就是使用lambda,它捕获的值
正在考虑的因素。所需的操作是
然后(map (lambda (j) (cons element j)) (permute sublist))
。现在我们
想要将此操作应用于列表的每个元素,以及方式
这是使用另一张地图,给出:
(map (lambda (element)
(lambda (j) (cons element j) (permute sublist)))
list)
现在,这看起来不错,但是存在一个问题:递归的每个阶段都需要单个
元素并将它们变成一个列表。这对于长度为1的列表来说很好,
但是对于更长的列表,它会针对每个递归调用重复,我们得到
非常深层次的嵌套列表。我们真正想做的就是全力以赴
这些列表位于相同的基础上,这正是(apply append ...)
所关注的内容。这几乎就是所有这一切。唯一的
缺少的是如何首先生成子列表。但
这也很简单 - 我们只使用remove
,因此sublist = (remove element list)
。把所有东西放在一起,我们有
(apply append (map (lambda (i)
(lambda (j) (cons i j))
(permute (remove i lst)))
lst))
基本案例负责长度= 1的案例,所有其他案件都可以从那里找到