Disons que j'ai une liste de n éléments, je sais qu'il y en a! façons possibles de commander ces éléments. Qu'est-ce qu'un algorithme pour générer tous les ordres possibles de cette liste? Exemple, j'ai la liste [a, b, c]. L'algorithme retournerait [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , une]].
Je lis ceci ici http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations
Mais Wikipedia n’a jamais été doué pour expliquer. Je ne comprends pas grand chose.
Fondamentalement, pour chaque élément de gauche à droite, toutes les permutations des éléments restants sont générées (et chaque ajout est ajouté aux éléments actuels). Cela peut être fait de manière récursive (ou itérative si vous aimez la douleur) jusqu'à ce que le dernier élément soit atteint, point auquel il n'y a qu'un seul ordre possible.
Ainsi, avec la liste [1,2,3,4], toutes les permutations commençant par 1 sont générées, puis toutes les permutations commençant par 2, puis 3, puis 4.
Cela réduit efficacement le problème consistant à trouver des permutations d'une liste de quatre éléments à une liste de trois éléments. Après avoir réduit à 2 et ensuite 1 listes d’éléments, elles seront toutes trouvées.
Exemple montrant les permutations de processus utilisant 3 billes colorées:
(from https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB.svg )
Voici un algorithme en Python qui fonctionne en place sur un tableau:
def permute(xs, low=0):
if low + 1 >= len(xs):
yield xs
else:
for p in permute(xs, low + 1):
yield p
for i in range(low + 1, len(xs)):
xs[low], xs[i] = xs[i], xs[low]
for p in permute(xs, low + 1):
yield p
xs[low], xs[i] = xs[i], xs[low]
for p in permute([1, 2, 3, 4]):
print p
Vous pouvez essayer le code par vous-même ici: http://repl.it/J9v
Il y a déjà beaucoup de bonnes solutions ici, mais je voudrais partager la façon dont j'ai résolu ce problème moi-même et espère que cela pourra être utile à quelqu'un qui voudrait également trouver sa propre solution.
Après avoir réfléchi au problème, j'ai tiré deux conclusions suivantes:
L
de taille n
, il y aura un nombre égal de solutions commençant par L1, L2 ... Ln éléments de la liste. Puisqu'il y a au total __ permutations n!
de la liste de taille n
, nous obtenons des permutations n! / n = (n-1)!
dans chaque groupe.[a,b]
et [b,a]
. En utilisant ces deux idées simples, j'ai dérivé l'algorithme suivant:
permute array
if array is of size 2
return first and second element as new array
return second and first element as new array
else
for each element in array
new subarray = array with excluded element
return element + permute subarray
Voici comment j'ai implémenté cela en C #:
public IEnumerable<List<T>> Permutate<T>(List<T> input)
{
if (input.Count == 2) // this are permutations of array of size 2
{
yield return new List<T>(input);
yield return new List<T> {input[1], input[0]};
}
else
{
foreach(T elem in input) // going through array
{
var rlist = new List<T>(input); // creating subarray = array
rlist.Remove(elem); // removing element
foreach(List<T> retlist in Permutate(rlist))
{
retlist.Insert(0,elem); // inserting the element at pos 0
yield return retlist;
}
}
}
}
La réponse de Wikipedia pour "ordre lexicographique" me semble parfaitement explicite dans le style des livres de recettes. Il cite une origine du 14ème siècle pour l'algorithme!
Je viens d'écrire une mise en œuvre rapide en Java de l'algorithme de Wikipédia comme vérification et ce n'était pas un problème. Mais ce que vous avez comme exemple dans votre Q n’est PAS "la liste de toutes les permutations", mais "une liste de toutes les permutations", de sorte que wikipedia ne vous aidera pas beaucoup. Vous avez besoin d'un langage dans lequel des listes de permutations sont construites de manière réaliste. Et croyez-moi, des listes de quelques milliards de dollars ne sont généralement pas traitées dans des langages impératifs. Vous voulez vraiment un langage de programmation fonctionnel non strict, dans lequel les listes sont un objet de première classe, pour sortir des choses tout en ne rapprochant pas la machine de la mort imminente de l'Univers.
C'est facile. En Haskell standard ou dans n’importe quel langage FP moderne:
-- perms of a list
perms :: [a] -> [ [a] ]
perms (a:as) = [bs ++ a:cs | perm <- perms as, (bs,cs) <- splits perm]
perms [] = [ [] ]
et
-- ways of splitting a list into two parts
splits :: [a] -> [ ([a],[a]) ]
splits [] = [ ([],[]) ]
splits (a:as) = ([],a:as) : [(a:bs,cs) | (bs,cs) <- splits as]
Comme l'a dit WhirlWind, vous commencez au début.
Vous échangez le curseur avec chaque valeur restante, y compris le curseur lui-même, il s’agit de nouvelles instances (j’ai utilisé un int[]
et un array.clone()
dans l’exemple).
Ensuite, effectuez des permutations sur toutes ces différentes listes, en vous assurant que le curseur est à droite.
Lorsqu'il n'y a plus de valeurs restantes (le curseur se trouve à la fin), imprimez la liste. C'est la condition d'arrêt.
public void permutate(int[] list, int pointer) {
if (pointer == list.length) {
//stop-condition: print or process number
return;
}
for (int i = pointer; i < list.length; i++) {
int[] permutation = (int[])list.clone();.
permutation[pointer] = list[i];
permutation[i] = list[pointer];
permutate(permutation, pointer + 1);
}
}
Récursif prend toujours un effort mental à maintenir. Et pour les gros nombres, la factorielle est facilement énorme et le débordement de pile sera facilement un problème.
Pour les petits nombres (3 ou 4, ce qui est le plus souvent rencontré), les boucles multiples sont assez simples et simples. Il est malheureux que les réponses avec des boucles n’aient pas été votées.
Commençons par l'énumération (plutôt que par permutation). Il suffit de lire le code en tant que pseudo code Perl.
$foreach $i1 in @list
$foreach $i2 in @list
$foreach $i3 in @list
print "$i1, $i2, $i3\n"
L'énumération est plus souvent rencontrée que la permutation, mais si une permutation est nécessaire, il suffit d'ajouter les conditions suivantes:
$foreach $i1 in @list
$foreach $i2 in @list
$if $i2==$i1
next
$foreach $i3 in @list
$if $i3==$i1 or $i3==$i2
next
print "$i1, $i2, $i3\n"
Maintenant, si vous avez vraiment besoin de la méthode générale potentiellement pour les grandes listes, nous pouvons utiliser la méthode radix. Considérons d’abord le problème d’énumération:
$n=@list
my @radix
$for $i=0:$n
$radix[$i]=0
$while 1
my @temp
$for $i=0:$n
Push @temp, $list[$radix[$i]]
print join(", ", @temp), "\n"
$call radix_increment
subcode: radix_increment
$i=0
$while 1
$radix[$i]++
$if $radix[$i]==$n
$radix[$i]=0
$i++
$else
last
$if $i>=$n
last
L'incrément de base est essentiellement le compte de nombre (dans la base du nombre d'éléments de liste).
Maintenant, si vous avez besoin de permutaion, ajoutez simplement les contrôles dans la boucle:
subcode: check_permutation
my @check
my $flag_dup=0
$for $i=0:$n
$check[$radix[$i]]++
$if $check[$radix[$i]]>1
$flag_dup=1
last
$if $flag_dup
next
Edit: Le code ci-dessus devrait fonctionner, mais pour permutation, radix_increment pourrait être un gaspillage. Donc, si le temps est une préoccupation pratique, nous devons changer radix_increment en permute_inc:
subcode: permute_init
$for $i=0:$n
$radix[$i]=$i
subcode: permute_inc
$max=-1
$for $i=$n:0
$if $max<$radix[$i]
$max=$radix[$i]
$else
$for $j=$n:0
$if $radix[$j]>$radix[$i]
$call swap, $radix[$i], $radix[$j]
break
$j=$i+1
$k=$n-1
$while $j<$k
$call swap, $radix[$j], $radix[$k]
$j++
$k--
break
$if $i<0
break
Bien sûr, maintenant que ce code est logiquement plus complexe, je vais partir pour l'exercice du lecteur.
Si quelqu'un se demande comment se faire en permutation en javascript.
Idea/pseudocode
par exemple. 'a' + permute (bc). le permute de bc serait bc & cb. Maintenant, ajoutez ces deux va donner abc, acb. de la même manière, choisissez b + permute (ac), vous obtiendrez un bac, un bca ... et vous poursuivrez.
regarde maintenant le code
function permutations(arr){
var len = arr.length,
perms = [],
rest,
picked,
restPerms,
next;
//for one or less item there is only one permutation
if (len <= 1)
return [arr];
for (var i=0; i<len; i++)
{
//copy original array to avoid changing it while picking elements
rest = Object.create(arr);
//splice removed element change array original array(copied array)
//[1,2,3,4].splice(2,1) will return [3] and remaining array = [1,2,4]
picked = rest.splice(i, 1);
//get the permutation of the rest of the elements
restPerms = permutations(rest);
// Now concat like a+permute(bc) for each
for (var j=0; j<restPerms.length; j++)
{
next = picked.concat(restPerms[j]);
perms.Push(next);
}
}
return perms;
}
Prenez votre temps pour comprendre cela. J'ai obtenu ce code de ( pertumation en JavaScript )
// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>
/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
/* Function to print permutations of string
This function takes three parameters:
1. String
2. Starting index of the string
3. Ending index of the string. */
void permute(char *a, int l, int r)
{
int i;
if (l == r)
printf("%s\n", a);
else
{
for (i = l; i <= r; i++)
{
swap((a+l), (a+i));
permute(a, l+1, r);
swap((a+l), (a+i)); //backtrack
}
}
}
/* Driver program to test above functions */
int main()
{
char str[] = "ABC";
int n = strlen(str);
permute(str, 0, n-1);
return 0;
}
Référence: Geeksforgeeks.org
void permutate(char[] x, int i, int n){
x=x.clone();
if (i==n){
System.out.print(x);
System.out.print(" ");
counter++;}
else
{
for (int j=i; j<=n;j++){
// System.out.print(temp); System.out.print(" "); //Debugger
swap (x,i,j);
// System.out.print(temp); System.out.print(" "+"i="+i+" j="+j+"\n");// Debugger
permutate(x,i+1,n);
// swap (temp,i,j);
}
}
}
void swap (char[] x, int a, int b){
char temp = x[a];
x[a]=x[b];
x[b]=temp;
}
J'ai créé celui-ci. basé sur la recherche aussi permutate (qwe, 0, qwe.length-1); Juste pour votre information, vous pouvez le faire avec ou sans retour en arrière
Version Java
/**
* @param uniqueList
* @param permutationSize
* @param permutation
* @param only Only show the permutation of permutationSize,
* else show all permutation of less than or equal to permutationSize.
*/
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
if (permutation == null) {
assert 0 < permutationSize && permutationSize <= uniqueList.size();
permutation = new ArrayList<>(permutationSize);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
}
}
for (int i : uniqueList) {
if (permutation.contains(i)) {
continue;
}
permutation.add(i);
if (!only) {
System.out.println(Arrays.toString(permutation.toArray()));
} else if (permutation.size() == permutationSize) {
System.out.println(Arrays.toString(permutation.toArray()));
}
if (permutation.size() < permutationSize) {
my_permutationOf(uniqueList, permutationSize, permutation, only);
}
permutation.remove(permutation.size() - 1);
}
}
Par exemple.
public static void main(String[] args) throws Exception {
my_permutationOf(new ArrayList<Integer>() {
{
add(1);
add(2);
add(3);
}
}, 3, null, true);
}
sortie:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
Un autre en Python, ce n'est pas en place comme @ cdiggins, mais je pense que c'est plus facile à comprendre
def permute(num):
if len(num) == 2:
# get the permutations of the last 2 numbers by swapping them
yield num
num[0], num[1] = num[1], num[0]
yield num
else:
for i in range(0, len(num)):
# fix the first number and get the permutations of the rest of numbers
for perm in permute(num[0:i] + num[i+1:len(num)]):
yield [num[i]] + perm
for p in permute([1, 2, 3, 4]):
print p
Voici une méthode Ruby jouet qui fonctionne comme #permutation.to_a
qui pourrait être plus lisible pour les fous. C'est lent, mais aussi 5 lignes.
def permute(ary)
return [ary] if ary.size <= 1
ary.collect_concat.with_index do |e, i|
rest = ary.dup.tap {|a| a.delete_at(i) }
permute(rest).collect {|a| a.unshift(e) }
end
end
Je pensais écrire un code pour obtenir les permutations d’un nombre entier quelconque, quelle que soit sa taille, c’est-à-dire qu’en fournissant un nombre 4567, nous obtenons toutes les permutations possibles jusqu’à 7654 ... Alors j’ai travaillé dessus et trouvé un algorithme que j’ai finalement mis en œuvre. est le code écrit en "c" . Vous pouvez simplement le copier et l'exécuter sur n'importe quel compilateur open source. Mais certaines failles attendent d’être déboguées. S'il vous plaît apprécier.
Code:
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
//PROTOTYPES
int fact(int); //For finding the factorial
void swap(int*,int*); //Swapping 2 given numbers
void sort(int*,int); //Sorting the list from the specified path
int imax(int*,int,int); //Finding the value of imax
int jsmall(int*,int); //Gives position of element greater than ith but smaller than rest (ahead of imax)
void perm(); //All the important tasks are done in this function
int n; //Global variable for input OR number of digits
void main()
{
int c=0;
printf("Enter the number : ");
scanf("%d",&c);
perm(c);
getch();
}
void perm(int c){
int *p; //Pointer for allocating separate memory to every single entered digit like arrays
int i, d;
int sum=0;
int j, k;
long f;
n = 0;
while(c != 0) //this one is for calculating the number of digits in the entered number
{
sum = (sum * 10) + (c % 10);
n++; //as i told at the start of loop
c = c / 10;
}
f = fact(n); //It gives the factorial value of any number
p = (int*) malloc(n*sizeof(int)); //Dynamically allocation of array of n elements
for(i=0; sum != 0 ; i++)
{
*(p+i) = sum % 10; //Giving values in dynamic array like 1234....n separately
sum = sum / 10;
}
sort(p,-1); //For sorting the dynamic array "p"
for(c=0 ; c<f/2 ; c++) { //Most important loop which prints 2 numbers per loop, so it goes upto 1/2 of fact(n)
for(k=0 ; k<n ; k++)
printf("%d",p[k]); //Loop for printing one of permutations
printf("\n");
i = d = 0;
i = imax(p,i,d); //provides the max i as per algo (i am restricted to this only)
j = i;
j = jsmall(p,j); //provides smallest i val as per algo
swap(&p[i],&p[j]);
for(k=0 ; k<n ; k++)
printf("%d",p[k]);
printf("\n");
i = d = 0;
i = imax(p,i,d);
j = i;
j = jsmall(p,j);
swap(&p[i],&p[j]);
sort(p,i);
}
free(p); //Deallocating memory
}
int fact (int a)
{
long f=1;
while(a!=0)
{
f = f*a;
a--;
}
return f;
}
void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
return;
}
void sort(int*p,int t)
{
int i,temp,j;
for(i=t+1 ; i<n-1 ; i++)
{
for(j=i+1 ; j<n ; j++)
{
if(*(p+i) > *(p+j))
{
temp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = temp;
}
}
}
}
int imax(int *p, int i , int d)
{
while(i<n-1 && d<n-1)
{
if(*(p+d) < *(p+d+1))
{
i = d;
d++;
}
else
d++;
}
return i;
}
int jsmall(int *p, int j)
{
int i,small = 32767,k = j;
for (i=j+1 ; i<n ; i++)
{
if (p[i]<small && p[i]>p[k])
{
small = p[i];
j = i;
}
}
return j;
}
J'ai écrit cette solution récursive dans ANSI C. Chaque exécution de la fonction Permutate fournit une permutation différente jusqu'à ce que toutes soient terminées. Les variables globales peuvent également être utilisées pour les variables fact et count.
#include <stdio.h>
#define SIZE 4
void Rotate(int vec[], int size)
{
int i, j, first;
first = vec[0];
for(j = 0, i = 1; i < size; i++, j++)
{
vec[j] = vec[i];
}
vec[j] = first;
}
int Permutate(int *start, int size, int *count)
{
static int fact;
if(size > 1)
{
if(Permutate(start + 1, size - 1, count))
{
Rotate(start, size);
}
fact *= size;
}
else
{
(*count)++;
fact = 1;
}
return !(*count % fact);
}
void Show(int vec[], int size)
{
int i;
printf("%d", vec[0]);
for(i = 1; i < size; i++)
{
printf(" %d", vec[i]);
}
putchar('\n');
}
int main()
{
int vec[] = { 1, 2, 3, 4, 5, 6 }; /* Only the first SIZE items will be permutated */
int count = 0;
do
{
Show(vec, SIZE);
} while(!Permutate(vec, SIZE, &count));
putchar('\n');
Show(vec, SIZE);
printf("\nCount: %d\n\n", count);
return 0;
}
public class PermutationGenerator
{
private LinkedList<List<int>> _permutationsList;
public void FindPermutations(List<int> list, int permutationLength)
{
_permutationsList = new LinkedList<List<int>>();
foreach(var value in list)
{
CreatePermutations(value, permutationLength);
}
}
private void CreatePermutations(int value, int permutationLength)
{
var node = _permutationsList.First;
var last = _permutationsList.Last;
while (node != null)
{
if (node.Value.Count < permutationLength)
{
GeneratePermutations(node.Value, value, permutationLength);
}
if (node == last)
{
break;
}
node = node.Next;
}
List<int> permutation = new List<int>();
permutation.Add(value);
_permutationsList.AddLast(permutation);
}
private void GeneratePermutations(List<int> permutation, int value, int permutationLength)
{
if (permutation.Count < permutationLength)
{
List<int> copyOfInitialPermutation = new List<int>(permutation);
copyOfInitialPermutation.Add(value);
_permutationsList.AddLast(copyOfInitialPermutation);
List<int> copyOfPermutation = new List<int>();
copyOfPermutation.AddRange(copyOfInitialPermutation);
int lastIndex = copyOfInitialPermutation.Count - 1;
for (int i = lastIndex;i > 0;i--)
{
int temp = copyOfPermutation[i - 1];
copyOfPermutation[i - 1] = copyOfPermutation[i];
copyOfPermutation[i] = temp;
List<int> perm = new List<int>();
perm.AddRange(copyOfPermutation);
_permutationsList.AddLast(perm);
}
}
}
public void PrintPermutations(int permutationLength)
{
int count = _permutationsList.Where(perm => perm.Count() == permutationLength).Count();
Console.WriteLine("The number of permutations is " + count);
}
}
en PHP
$set=array('A','B','C','D');
function permutate($set) {
$b=array();
foreach($set as $key=>$value) {
if(count($set)==1) {
$b[]=$set[$key];
}
else {
$subset=$set;
unset($subset[$key]);
$x=permutate($subset);
foreach($x as $key1=>$value1) {
$b[]=$value.' '.$value1;
}
}
}
return $b;
}
$x=permutate($set);
var_export($x);
Voici le code en Python pour imprimer toutes les permutations possibles d'une liste:
def next_perm(arr):
# Find non-increasing suffix
i = len(arr) - 1
while i > 0 and arr[i - 1] >= arr[i]:
i -= 1
if i <= 0:
return False
# Find successor to pivot
j = len(arr) - 1
while arr[j] <= arr[i - 1]:
j -= 1
arr[i - 1], arr[j] = arr[j], arr[i - 1]
# Reverse suffix
arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
print arr
return True
def all_perm(arr):
a = next_perm(arr)
while a:
a = next_perm(arr)
arr = raw_input()
arr.split(' ')
arr = map(int, arr)
arr.sort()
print arr
all_perm(arr)
J'ai utilisé un algorithme d'ordre lexicographique pour obtenir toutes les permutations possibles, mais un algorithme récursif est plus efficace. Vous pouvez trouver le code de l'algorithme récursif ici: Permutation de récursivité Python
Voici une implémentation pour ColdFusion (requiert CF10 en raison de l'argument de fusion de ArrayAppend ()):
public array function permutateArray(arr){
if (not isArray(arguments.arr) ) {
return ['The ARR argument passed to the permutateArray function is not of type array.'];
}
var len = arrayLen(arguments.arr);
var perms = [];
var rest = [];
var restPerms = [];
var rpLen = 0;
var next = [];
//for one or less item there is only one permutation
if (len <= 1) {
return arguments.arr;
}
for (var i=1; i <= len; i++) {
// copy the original array so as not to change it and then remove the picked (current) element
rest = arraySlice(arguments.arr, 1);
arrayDeleteAt(rest, i);
// recursively get the permutation of the rest of the elements
restPerms = permutateArray(rest);
rpLen = arrayLen(restPerms);
// Now concat each permutation to the current (picked) array, and append the concatenated array to the end result
for (var j=1; j <= rpLen; j++) {
// for each array returned, we need to make a fresh copy of the picked(current) element array so as to not change the original array
next = arraySlice(arguments.arr, i, 1);
arrayAppend(next, restPerms[j], true);
arrayAppend(perms, next);
}
}
return perms;
}
Basé sur la solution js de KhanSharp ci-dessus.
ceci est une version Java pour permutation
public class Permutation {
static void permute(String str) {
permute(str.toCharArray(), 0, str.length());
}
static void permute(char [] str, int low, int high) {
if (low == high) {
System.out.println(str);
return;
}
for (int i=low; i<high; i++) {
swap(str, i, low);
permute(str, low+1, high);
swap(str, low, i);
}
}
static void swap(char [] array, int i, int j) {
char t = array[i];
array[i] = array[j];
array[j] = t;
}
}
En scala
def permutazione(n: List[Int]): List[List[Int]] = permutationeAcc(n, Nil)
def permutationeAcc(n: List[Int], acc: List[Int]): List[List[Int]] = {
var result: List[List[Int]] = Nil
for (i ← n if (!(acc contains (i))))
if (acc.size == n.size-1)
result = (i :: acc) :: result
else
result = result ::: permutationeAcc(n, i :: acc)
result
}
Dans la solution Java suivante, nous exploitons le fait que les chaînes sont immuables pour éviter de cloner l'ensemble des résultats à chaque itération.
L'entrée sera une chaîne, dites "abc", et le résultat sera toutes les permutations possibles:
abc
acb
bac
bca
cba
cab
public static void permute(String s) {
permute(s, 0);
}
private static void permute(String str, int left){
if(left == str.length()-1) {
System.out.println(str);
} else {
for(int i = left; i < str.length(); i++) {
String s = swap(str, left, i);
permute(s, left+1);
}
}
}
private static String swap(String s, int left, int right) {
if (left == right)
return s;
String result = s.substring(0, left);
result += s.substring(right, right+1);
result += s.substring(left+1, right);
result += s.substring(left, left+1);
result += s.substring(right+1);
return result;
}
La même approche peut être appliquée aux tableaux (au lieu d'une chaîne):
public static void main(String[] args) {
int[] abc = {1,2,3};
permute(abc, 0);
}
public static void permute(int[] arr, int index) {
if (index == arr.length) {
System.out.println(Arrays.toString(arr));
} else {
for (int i = index; i < arr.length; i++) {
int[] permutation = arr.clone();
permutation[index] = arr[i];
permutation[i] = arr[index];
permute(permutation, index + 1);
}
}
}
Vous ne pouvez pas vraiment parler de la résolution d'un problème de permultation dans une récursivité sans poster une implémentation dans un (dialecte de) langue qui a été à l'origine de l'idée . Donc, par souci d'exhaustivité, voici l'une des manières de procéder dans Scheme.
(define (permof wd)
(cond ((null? wd) '())
((null? (cdr wd)) (list wd))
(else
(let splice ([l '()] [m (car wd)] [r (cdr wd)])
(append
(map (lambda (x) (cons m x)) (permof (append l r)))
(if (null? r)
'()
(splice (cons m l) (car r) (cdr r))))))))
appelant (permof (list "foo" "bar" "baz"))
nous aurons:
'(("foo" "bar" "baz")
("foo" "baz" "bar")
("bar" "foo" "baz")
("bar" "baz" "foo")
("baz" "bar" "foo")
("baz" "foo" "bar"))
Je n'entrerai pas dans les détails de l'algorithme car il a été suffisamment expliqué dans d'autres messages. L'idée est la même.
Cependant, les problèmes récursifs ont tendance à être beaucoup plus difficiles à modéliser et à envisager dans un média destructeur tel que Python, C et Java, alors que dans LISP ou ML, cela peut être exprimé de manière concise.
C'est ma solution sur Java:
public class CombinatorialUtils {
public static void main(String[] args) {
List<String> alphabet = new ArrayList<>();
alphabet.add("1");
alphabet.add("2");
alphabet.add("3");
alphabet.add("4");
for (List<String> strings : permutations(alphabet)) {
System.out.println(strings);
}
System.out.println("-----------");
for (List<String> strings : combinations(alphabet)) {
System.out.println(strings);
}
}
public static List<List<String>> combinations(List<String> alphabet) {
List<List<String>> permutations = permutations(alphabet);
List<List<String>> combinations = new ArrayList<>(permutations);
for (int i = alphabet.size(); i > 0; i--) {
final int n = i;
combinations.addAll(permutations.stream().map(strings -> strings.subList(0, n)).distinct().collect(Collectors.toList()));
}
return combinations;
}
public static <T> List<List<T>> permutations(List<T> alphabet) {
ArrayList<List<T>> permutations = new ArrayList<>();
if (alphabet.size() == 1) {
permutations.add(alphabet);
return permutations;
} else {
List<List<T>> subPerm = permutations(alphabet.subList(1, alphabet.size()));
T addedElem = alphabet.get(0);
for (int i = 0; i < alphabet.size(); i++) {
for (List<T> permutation : subPerm) {
int index = i;
permutations.add(new ArrayList<T>(permutation) {{
add(index, addedElem);
}});
}
}
}
return permutations;
}
}
Je sais que c'est un sujet très très ancien et même hors-sujet dans le stackoverflow d'aujourd'hui, mais je voulais tout de même apporter une réponse javascript amicale pour la simple raison qu'il fonctionne dans votre navigateur.
J'ai également ajouté le point d'arrêt de la directive debugger
afin que vous puissiez parcourir le code (chrome requis) pour voir le fonctionnement de cet algorithme. Ouvrez votre console de développement en chrome (F12
dans Windows ou CMD + OPTION + I
sur mac), puis cliquez sur "Exécuter l'extrait de code". Cela implémente le même algorithme que celui présenté par @WhirlWind dans sa réponse.
Votre navigateur doit suspendre l'exécution à la directive debugger
. Utilisez F8
pour continuer l'exécution du code.
function permute(rest, prefix = []) {
if (rest.length === 0) {
return [prefix];
}
return (rest
.map((x, index) => {
const oldRest = rest;
const oldPrefix = prefix;
// the `...` destructures the array into single values flattening it
const newRest = [...rest.slice(0, index), ...rest.slice(index + 1)];
const newPrefix = [...prefix, x];
debugger;
const result = permute(newRest, newPrefix);
return result;
})
// this step flattens the array of arrays returned by calling permute
.reduce((flattened, arr) => [...flattened, ...arr], [])
);
}
console.log(permute([1, 2, 3]));
Voici un algorithme en R, au cas où quelqu'un aurait besoin d'éviter de charger des bibliothèques supplémentaires comme je le devais.
permutations <- function(n){
if(n==1){
return(matrix(1))
} else {
sp <- permutations(n-1)
p <- nrow(sp)
A <- matrix(nrow=n*p,ncol=n)
for(i in 1:n){
A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
}
return(A)
}
}
Exemple d'utilisation:
> matrix(letters[permutations(3)],ncol=3)
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
C'est un code récursif pour Java, l'idée est d'avoir un préfixe qui ajoute le reste des caractères:
public static void permutation(String str) {
permutation("", str);
}
private static void permutation(String prefix, String str) {
int n = str.length();
if (n == 0) System.out.println(prefix);
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str);
}
}
Exemple:
Entrée = "ABC"; Sortie:
ABCACBBACBCACABCBA
Voici une solution non récursive en C++ qui fournit la permutation suivante par ordre croissant, de la même manière que la fonctionnalité fournie par std :: next_permutation:
void permute_next(vector<int>& v)
{
if (v.size() < 2)
return;
if (v.size() == 2)
{
int tmp = v[0];
v[0] = v[1];
v[1] = tmp;
return;
}
// Step 1: find first ascending-ordered pair from right to left
int i = v.size()-2;
while(i>=0)
{
if (v[i] < v[i+1])
break;
i--;
}
if (i<0) // vector fully sorted in descending order (last permutation)
{
//resort in ascending order and return
sort(v.begin(), v.end());
return;
}
// Step 2: swap v[i] with next higher element of remaining elements
int pos = i+1;
int val = v[pos];
for(int k=i+2; k<v.size(); k++)
if(v[k] < val && v[k] > v[i])
{
pos = k;
val = v[k];
}
v[pos] = v[i];
v[i] = val;
// Step 3: sort remaining elements from i+1 ... end
sort(v.begin()+i+1, v.end());
}
#!/usr/bin/env python
import time
def permutations(sequence):
# print sequence
unit = [1, 2, 1, 2, 1]
if len(sequence) >= 4:
for i in range(4, (len(sequence) + 1)):
unit = ((unit + [i - 1]) * i)[:-1]
# print unit
for j in unit:
temp = sequence[j]
sequence[j] = sequence[0]
sequence[0] = temp
yield sequence
else:
print 'You can use PEN and PAPER'
# s = [1,2,3,4,5,6,7,8,9,10]
s = [x for x in 'PYTHON']
print s
z = permutations(s)
try:
while True:
# time.sleep(0.0001)
print next(z)
except StopIteration:
print 'Done'
['P', 'Y', 'T', 'H', 'O', 'N']
['Y', 'P', 'T', 'H', 'O', 'N']
['T', 'P', 'Y', 'H', 'O', 'N']
['P', 'T', 'Y', 'H', 'O', 'N']
['Y', 'T', 'P', 'H', 'O', 'N']
['T', 'Y', 'P', 'H', 'O', 'N']
['H', 'Y', 'P', 'T', 'O', 'N']
['Y', 'H', 'P', 'T', 'O', 'N']
['P', 'H', 'Y', 'T', 'O', 'N']
['H', 'P', 'Y', 'T', 'O', 'N']
['Y', 'P', 'H', 'T', 'O', 'N']
['P', 'Y', 'H', 'T', 'O', 'N']
['T', 'Y', 'H', 'P', 'O', 'N']
['Y', 'T', 'H', 'P', 'O', 'N']
['H', 'T', 'Y', 'P', 'O', 'N']
['T', 'H', 'Y', 'P', 'O', 'N']
['Y', 'H', 'T', 'P', 'O', 'N']
['H', 'Y', 'T', 'P', 'O', 'N']
['P', 'Y', 'T', 'H', 'O', 'N']
.
.
.
['Y', 'T', 'N', 'H', 'O', 'P']
['N', 'T', 'Y', 'H', 'O', 'P']
['T', 'N', 'Y', 'H', 'O', 'P']
['Y', 'N', 'T', 'H', 'O', 'P']
['N', 'Y', 'T', 'H', 'O', 'P']
Cela les produit une à une sans créer de liste - le même résultat final que la réponse de Marios Choudary (ou simplement en appelant nextPermute de C++, lorsque Anders répondra aux notes). Mais c'est l'algorithme de Heap (la version non récursive) ré-arrangé et une classe pour sauvegarder le contexte. Utilisé comme:
P5=new genPermutes_t(5); // P5.P is now [0,1,2,3,4]
while(!P5.isDone()) {
// use P5.P here
P5.next();
}
Le code est en C # sans être une approbation. Les variables sont telles quelles du pseudocode de Heap, auquel les commentaires font également référence:
public class genPermutes_t {
public int[] P; // the current permuation
private int n, i; // vars from the original algorithm
private int[] c; // ditto
public genPermutes_t(int count) {
// init algorithm:
n=count;
i=0;
c=new int[n];
for(int j=0;j<n;j++) c[j]=0;
// start current permutation as 0,1 ... n-1:
P=new int[n];
for(int j=0;j<n;j++) P[j]=j;
}
public bool isDone() {
return i>=n; // condition on the original while loop
}
public void next() {
// the part of the loop that spins until done or ready for next permute:
while(i<n && c[i]>=i) {
c[i]=0;
i++;
}
// pulled from inside loop -- the part that makes next permute:
if(i<n) { // if not done
if(i%2==0) swap(0,i);
else swap(c[i], i);
// "print P" removed. User will simply examine it
c[i]+=1;
i=0;
}
}
private void swap(int i1, int i2) {int tmp=P[i1]; P[i1]=P[i2]; P[i2]=tmp;}
}
Juste pour être complet, C++
#include <iostream>
#include <algorithm>
#include <string>
std::string theSeq = "abc";
do
{
std::cout << theSeq << endl;
}
while (std::next_permutation(theSeq.begin(), theSeq.end()));
...
abc
acb
bac
bca
cab
cba
Solution Bourne Shell - sur un total de quatre lignes (sans test pour aucun cas param):
test $# -eq 1 && echo "$1" && exit
for i in $*; do
$0 `echo "$*" | sed -e "s/$i//"` | sed -e "s/^/$i /"
done
Voici une solution récursive en PHP. Le message de WhirlWind décrit précisément la logique. Il est à noter que la génération de toutes les permutations s'exécute en temps factoriel, il peut donc être judicieux d'utiliser une approche itérative.
public function permute($sofar, $input){
for($i=0; $i < strlen($input); $i++){
$diff = strDiff($input,$input[$i]);
$next = $sofar.$input[$i]; //next contains a permutation, save it
$this->permute($next, $diff);
}
}
La fonction strDiff prend deux chaînes, s1
et s2
, et renvoie une nouvelle chaîne avec tout ce qui est dans s1
sans éléments dans s2
(les doublons importent). Donc, strDiff('finish','i')
=> 'fnish'
(le second 'i' est pas enlevé).