我正在尝试编写一个Common Lisp函数,它将为我提供列表的所有可能排列,仅使用每个元素一次。例如,列表'(1 2 3)将给出输出((1 2 3)(1 3 2)(2 1 3)(2 3 1)(3 1 2)(3 2 1))。
我已经写了一些有用的东西,但它很笨重,它并不总是有效,我甚至都不理解它。我不是要求代码,也可能是关于如何思考它的一些指导。我对编写算法知之甚少。
谢谢, 杰森
答案 0 :(得分:15)
作为一种基本方法,“所有排列”都遵循这种递归模式:
all permutations of a list L is: for each element E in L: that element prepended to all permutations of [ L with E removed ]
如果我们认为您的列表中没有重复元素,则应执行以下操作:
(defun all-permutations (list) (cond ((null list) nil) ((null (cdr list)) (list list)) (t (loop for element in list append (mapcar (lambda (l) (cons element l)) (all-permutations (remove element list)))))))
答案 1 :(得分:8)
这是允许重复元素的答案。代码更加“低迷”,因为它不使用循环,缺点是比Rainer Joswig的解决方案更难以理解:
(defun all-permutations (lst &optional (remain lst))
(cond ((null remain) nil)
((null (rest lst)) (list lst))
(t (append
(mapcar (lambda (l) (cons (first lst) l))
(all-permutations (rest lst)))
(all-permutations (append (rest lst) (list (first lst))) (rest remain))))))
可选的retain参数用于cdring down list,在进入递归之前旋转列表元素。
答案 2 :(得分:3)
浏览列表,依次选择每个元素。该元素将是您当前排列的第一个元素。
将该元素包含在剩余元素的所有排列中。
答案 3 :(得分:-2)
我不确定你的问题是关于Common Lisp,还是关于算法。
这里有其他语言的类似问题(和解决方案),例如Python。 Python通常可以逐行转换为Common Lisp,所以选择一个并移植它? : - )