Как я могу получить все возможные перестановки списка с помощью Common Lisp?

Я пытаюсь написать функцию Common Lisp, которая даст мне все возможные перестановки списка, используя каждый элемент только один раз. Например, список '(1 2 3) даст выход ((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1)).

Я уже писал что-то подобное, но он неуклюж, он не всегда работает, и я даже не понимаю его. Я не прошу код, просто, может быть, для некоторых советов о том, как думать об этом. Я мало знаю о написании алгоритмов.

Спасибо, Джейсон

Ответ 1

В качестве базового подхода "все перестановки" следуют этому рекурсивному шаблону:

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

Ответ 2

Вот ответ, который позволяет повторять элементы. Код еще более "lispish", поскольку он не использует цикл, причем недостатком является менее понятное, чем решение 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))))))

Необязательный аргумент останова используется для cdring в списке, вращая элементы списка перед входом в рекурсию.

Ответ 3

Пройдитесь по списку, выбирая каждый элемент по очереди. Этот элемент будет первым элементом вашей текущей перестановки.

Мигает этот элемент ко всем перестановкам остальных элементов.

Ответ 4

Я не уверен, что ваш вопрос об Common Lisp, или об алгоритме.

Здесь существуют похожие проблемы (и решения) для других языков, например Python. Python часто может быть переведен в Common Lisp виртуально для линии, поэтому выберите один и поместите его?: -)