Скажем, у меня есть список из n элементов, я знаю, что есть n! возможные способы заказа этих элементов. Каков алгоритм создания всех возможных порядков этого списка? Например, у меня есть список [a, b, c]. Алгоритм вернет [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , а]].
Я читаю это здесь http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations
Но Википедия никогда не могла объяснить. Я не очень понимаю в этом.
algorithm
list
permutation
Fent
источник
источник
Ответы:
По сути, для каждого элемента слева направо генерируются все перестановки оставшихся элементов (и каждый добавляется с текущими элементами). Это можно делать рекурсивно (или итеративно, если вам нравится боль) до тех пор, пока не будет достигнут последний элемент, и в этот момент существует только один возможный порядок.
Итак, со списком [1,2,3,4] генерируются все перестановки, начинающиеся с 1, затем все перестановки, начинающиеся с 2, затем 3, затем 4.
Это эффективно сокращает задачу от поиска перестановок списка из четырех элементов до списка из трех элементов. После сокращения до 2, а затем 1 списков, все они будут найдены.
Пример, показывающий перестановки процессов с использованием 3 цветных шариков:
(из https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB. svg )
источник
Вот алгоритм в Python, который работает с массивом:
Вы можете попробовать этот код здесь: http://repl.it/J9v
источник
Здесь уже есть много хороших решений, но я хотел бы поделиться тем, как я решил эту проблему самостоятельно, и надеюсь, что это может быть полезно для кого-то, кто также хотел бы получить свое собственное решение.
Поразмыслив над проблемой, я пришел к двум следующим выводам:
L
размераn
будет одинаковое количество решений, начиная с L 1 , L 2 ... L n элементов списка. Так как всего естьn!
перестановки списка размераn
, мы получаемn! / n = (n-1)!
перестановки в каждой группе.[a,b]
и[b,a]
.Используя эти две простые идеи, я вывел следующий алгоритм:
Вот как я реализовал это на C #:
источник
Ответ Википедии на «лексикографический порядок» мне кажется совершенно ясным в стиле поваренной книги. Он ссылается на происхождение алгоритма 14 века!
Я только что написал быструю реализацию алгоритма Википедии на Java в качестве проверки, и это не было проблемой. Но то, что у вас есть в вашем Q в качестве примера, - это НЕ «список всех перестановок», а «СПИСОК всех перестановок», так что википедия вам не очень поможет. Вам нужен язык, на котором можно построить списки перестановок. И поверьте мне, списки длиной в несколько миллиардов обычно не обрабатываются в императивных языках. Вам действительно нужен нестрогий функциональный язык программирования, в котором списки являются первоклассным объектом, чтобы вытащить вещи, не приближая машину к тепловой смерти Вселенной.
Это легко. В стандартном Haskell или любом современном языке FP:
и
источник
Как сказал WhirlWind, вы начинаете с самого начала.
Вы меняете местами курсор с каждым оставшимся значением, включая сам курсор, это все новые экземпляры (я использовал
int[]
иarray.clone()
в примере).Затем выполните перестановки во всех этих разных списках, убедившись, что курсор находится один вправо.
Когда больше нет оставшихся значений (курсор находится в конце), распечатайте список. Это условие остановки.
источник
Рекурсивный всегда требует некоторых умственных усилий для поддержания. А для больших чисел факториал легко огромен, и переполнение стека легко может стать проблемой.
Для небольших чисел (3 или 4, что чаще всего встречается) несколько циклов довольно просты и понятны. К сожалению, ответы с циклами не получили голосования.
Начнем с перечисления (а не перестановки). Просто прочтите этот код как псевдо-код Perl.
Перечисление встречается чаще, чем перестановка, но если перестановка нужна, просто добавьте условия:
Теперь, если вам действительно нужен общий метод потенциально для больших списков, мы можем использовать метод radix. Во-первых, рассмотрим проблему перечисления:
Приращение по основанию - это, по сути, подсчет чисел (на основе количества элементов списка).
Теперь, если вам нужна перестановка, просто добавьте проверки внутри цикла:
Изменить: приведенный выше код должен работать, но для перестановки radix_increment может быть расточительным. Поэтому, если время имеет практическое значение, мы должны изменить radix_increment на permute_inc:
Конечно, теперь этот код логически более сложен, я оставлю для читателя упражнения.
источник
Ссылка: Geeksforgeeks.org
источник
Если кому интересно, как сделать перестановку в javascript.
Идея / псевдокод
например. 'а' + перестановка (до н.э.). перестановка bc будет bc & cb. Теперь добавьте эти два и получите abc, acb. аналогично, выберите b + permute (ac), чтобы проверить bac, bca ... и продолжить.
теперь посмотри на код
Найдите время, чтобы понять это. Я получил этот код из ( пертумация в JavaScript )
источник
Еще один в Python, его нет, как @ cdiggins, но я думаю, что его легче понять
источник
Я думал о написании кода для получения перестановок любого заданного целого числа любого размера, то есть, предоставляя число 4567, мы получаем все возможные перестановки до 7654 ... Итак, я работал над ним, нашел алгоритм и, наконец, реализовал его, Вот это код, написанный на "c". Вы можете просто скопировать его и запустить на любых компиляторах с открытым исходным кодом. Но некоторые недоработки ждут своего часа. Пожалуйста, оцените.
Код:
источник
Я создал это. на основе слишком перестановочного исследования (qwe, 0, qwe.length-1); Просто чтобы вы знали, вы можете сделать это с возвратом или без него
источник
Вот такой игрушечный метод на Ruby,
#permutation.to_a
который может быть более понятным для сумасшедших. Это чертовски медленно, но тоже 5 строк.источник
Я написал это рекурсивное решение на ANSI C. Каждое выполнение функции Permutate обеспечивает одну другую перестановку, пока все не будут выполнены. Глобальные переменные также могут использоваться для переменных fact и count.
источник
Версия Java
Например
вывод:
источник
в PHP
источник
Вот код на Python для печати всех возможных перестановок списка:
Я использовал алгоритм лексикографического порядка, чтобы получить все возможные перестановки, но рекурсивный алгоритм более эффективен. Вы можете найти код для рекурсивного алгоритма здесь: Перестановки рекурсии Python
источник
источник
В Scala
источник
это версия Java для перестановки
источник
Вот реализация ColdFusion (требуется CF10 из-за аргумента слияния для ArrayAppend ()):
На основе решения KhanSharp js выше.
источник
Я знаю, что это очень-очень старый и даже не по теме в сегодняшнем stackoverflow, но я все же хотел внести дружественный ответ javascript по той простой причине, что он работает в вашем браузере.
Я также добавил
debugger
точку останова директивы, чтобы вы могли пройти через код (требуется хром), чтобы увидеть, как работает этот алгоритм. Откройте консоль разработчика в Chrome (F12
в Windows илиCMD + OPTION + I
Mac) и нажмите «Выполнить фрагмент кода». Это реализует тот же алгоритм, который @WhirlWind представил в своем ответе.Ваш браузер должен приостановить выполнение
debugger
директивы. ИспользуйтеF8
для продолжения выполнения кода.Просмотрите код и посмотрите, как он работает!
источник
В следующем решении Java мы используем тот факт, что строки неизменяемы, чтобы избежать клонирования набора результатов при каждой итерации.
На входе будет строка, скажем "abc", а на выходе будут все возможные варианты:
Код:
Тот же подход можно применить к массивам (вместо строки):
источник
Это мое решение на Java:
источник
Вы не можете говорить о решении проблемы перестановки в рекурсии, не опубликовав реализацию на (диалекте) языка, на котором впервые возникла эта идея . Итак, для полноты, вот один из способов, который можно сделать в Scheme.
позвонив
(permof (list "foo" "bar" "baz"))
мы получим:Я не буду вдаваться в подробности алгоритма, потому что он достаточно объяснен в других сообщениях. Идея та же.
Однако рекурсивные проблемы, как правило, намного сложнее моделировать и обдумывать в деструктивной среде, такой как Python, C и Java, в то время как в Lisp или ML это можно выразить кратко.
источник
Вот рекурсивное решение на PHP. Пост WhirlWind точно описывает логику. Стоит упомянуть, что генерация всех перестановок выполняется за факториальное время, поэтому было бы неплохо использовать вместо этого итеративный подход.
Функция strDiff принимает две строки
s1
иs2
, и возвращает новую строку со всемs1
без элементов внутриs2
(дублирует вопрос). Итак,strDiff('finish','i')
=>'fnish'
(второе «i» не удаляется).источник
Вот алгоритм на R на тот случай, если кому-то нужно избежать загрузки дополнительных библиотек, как это было нужно мне.
Пример использования:
источник
источник
Это рекурсивный код для java, идея состоит в том, чтобы иметь префикс, добавляющий остальные символы:
Пример:
Input = "ABC"; Вывод:
ABC ACB BAC BCA CAB CBA
источник
str
при рекурсивном вызове, иначе он не завершится.Для полноты: C ++
...
источник
Вот нерекурсивное решение на C ++, которое обеспечивает следующую перестановку в порядке возрастания, аналогично функциональности, предоставляемой std :: next_permutation:
источник