next up previous contents index
suivant: Récupérer et installer un monter: Les permutations précédent: Les permutations circulaires   Table des matières   Index

Programme donnant toutes les permutations

1/ En faisant n=size(l) appels récursifs.
Les fonctions que l'on va écrire vont utiliser la fonction echange.
//echange ds l les elements d'indices j et k
echange(l,j,k):={
local a;
a:=l[j];
l[j]:=l[k];
l[k]:=a;
return l;
};

On peut décrire l'arbre des permutations de la liste l :
à partir de la racine on a n=size(l) branches. Chaque branche commence respectivement par chacun des éléments de la liste l.
On va donc parcourir cet arbre de la racine (n\oeud de niveau 0) aux différentes extrémités, en renvoyant la liste des branches parcourues pour arriver à cette extrémité.
On va parcourir cet arbre en parcourant les n branches. On numérote ces branches par p = 1..n et le niveau des n\oeuds q = 0..n.
On aura donc n appels récursifs.
Chaque branche p peut être considérée à leur tour comme un arbre ayant n - 1 branches.La branche p aboutit aux permutations qui laissent invariant le p-ième élément de l (l[p - 1]). C'est cet élément que l'on va échanger avec l[0] pour que chaque branche p laisse invariant l' élément l[0].
On sait que l'on est arrivé au bout de la branche, quand on se trouve au n\oeud de niveau n - 1, dans ce cas la permutation chechée est l (c'est la permutation obtenue à partir de l en laissant ces n - 1 premiers éléments invariants).
On utilise une variable locale lr, égale à la liste à renvoyer et un paramètre k, pour que permus(l,k) renvoie toutes les permutations de l qui laissent invariant les k premiers éléments de l. On tape :

//utilise echange et la variable locale lr (liste resultat)
//permus(l,k) laisse invariant les k premiers elements de l
//permus([1,2,3,4],0); renvoie toutes les permutations de l 
permus(l,k):={
local lr;
if (k==size(l)-1) return [l];
lr:=[];
for (j:=k;j<size(l);j++){
l:=echange(l,k,j);
lr:=[op(lr),op(permus(l,k+1))];
l:=echange(l,j,k);
}
return lr;
};
On n'est pas obligé de remettre la suite l à sa valeur de départ pour recommencer l'itération puisque le premier échange dans l'itération revient à transformer l en la liste où on a mis son j-ième élément en tête (j = 0..n - 1).
//utilise echange permuts([1,2,3,4],0)
//la 2ieme instruction echange est inutile car on echange 
// 0 et 1 ([1,0,2..]) puis 0 et 2 ([2,0,1..]) etc
//avec la 2ieme instruction echange, on echange
//0 et 1 ([1,0,2..]) puis 0 et 2 ([2,1,0..]) etc
permuts(l,k):={
local lr;
if (k==size(l)-1) return [l];
lr:=[];
for (j:=k;j<size(l);j++){
l:=echange(l,k,j);
lr:=[op(lr),op(permuts(l,k+1))];
}
return lr;
};

Comme il faut 2 paramètres pour écrire la fonction récursive permuts, on écrit la fonction permutation qui utilise permuts:

//l:=[1,2,3];permutation(l); 
//renvoie toutes les permutations de l
//utilise permuts
permutation(l):={
return permuts(l,0);
};
On tape :
permutation([1,2,3])
On obtient :
[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
On peut aussi écrire une autre fonction récursive ayant comme paramètre ld et lf. ld contient les premières valeurs de l qui seront inchangées dans la permutation et lf contient les valeurs restantes de l, celles qui restent à permuter. On remarquera que l'on utilise le resultat mis dans res est ici une séquence.
//au debut ld=[] et lf=l,
//groupe_s([],l) renvoie toutes les permutations de l
groupe_s(ld,lf):={
 local j,n,res;
 n:=size(lf);
 res:=NULL;
 if (n==1)
   return concat(ld,lf);
 for (j:=0;j<n;j++){
   res:=res,groupe_s(append(ld,lf[0]),tail(lf));
   // permutation circulaire
   lf:=append(tail(lf),lf[0]);
 }
 return res;
};
Et la fonction groupesym qui utilise la fonction récursive groupe_s :
//utilise groupe_s
//groupesym(l) renvoie toutes les permutations de l
groupesym(l):=return(groupe_s([],l));
2/ En faisant 2 appels récursifs.
Cet algorithme est surtout fait pour des langages qui n'ont pas de boucle for.
Les fonctions vont utiliser la fonction circulaire (pour plus de clareté), puis on remplacera circulaire(l) par concat(tail(l),l[0]).
//l:=[1,2,3]; circulaire(l) 
//renvoie la liste l ou la tete est mise a la fin. 
circulaire(l):={
return concat(tail(l),l[0]);
};
On peut décrire l'arbre des permutations de la liste l :
à partir de la racine on a n=size(l) branches. Chaque branche commence par chacun des éléments de la liste l.
On va parcourir cet arbre, en parcourant la premiére branche, puis en considérant qu'il reste à parcourir un arbre de n - 1 branches.
On aura donc 2 appels récursifs.
Pour le parcours de la première branche, il faut connaitre la liste des éléments qui nous a permis d'arriver à un n\oeud donné, c'est cette liste que l'on met dans ldl, l contenant les éléments qu'il faut encore permuter. On s'arrête quand l=[], et le résultat est [ldl].
Pour le parcours des n - 1 branches restantes, on change pour chaque branche la liste à permuter en circulaire(l).
Il faut un test d'arrêt pour ce parcours, pour cela on a besoin d'un paramètre supplementaire qui sera ld (liste de référence égale à l au départ) dans permss ou qui sera n (longueur de l au départ) dans permss1.
On écrit permss :
// utilise circulaire, l:=[1,2];permss([],l,l);
//ldl=debut de l, l=liste a permuter, 
//ld=liste de reference (=l au debut)
permss(ldl,l,ld):={
if (l==[]) return [ldl];
if (ld==[]) return ld;
return [op(permss(concat(ldl,l[0]),tail(l),tail(l))),
        op(permss(ldl,circulaire(l),tail(ld)))];
};
On écrit permss1 qui utilise comme paramètre n qui représente la longueur de la liste qui reste à permuter (n=size(l) au départ) :
//utilise circulaire, l:=[1,2,3,4];permss1([],l,size(l)); 
//ldl=debut de l, l=liste a permuter, n=size(l) au debut
permss1(ldl,l,n):={
if (l==[]) return [ldl];
if (n==0) return [];
return [op(permss1(concat(ldl,l[0]),tail(l),size(tail(l)))),
        op(permss1(ldl,circulaire(l),n-1))];
};
On a aussi écrit la fonction permss2 contenant une variable locale lr qui est la liste à renvoyer et qui donne un algorithme plus lisible.
//l:=[1,2];permss2([],l,l); 
//ldl=debut de l, l=liste a permuter,
//ld=liste de reference (=l au debut)
// lr liste a renvoyer en variable locale
permss2(ldl,l,ld):={
local lr;
if (l==[]) return [ldl];
if (ld==[]) return [];
lr:=permss2(concat(ldl,l[0]),tail(l),tail(l));
lr:=append(lr,op(permss2(ldl,concat(tail(l),l[0]),tail(ld))));
return lr
};
puis la fonction permute qui utilise permss2 :
//utilise permss2, 
//permute(l) renvoie toutes les permutations de l
permute(l):={
return permss2([],l,l);
};
On tape :
permute([1,2,3])
On obtient :
[[1,2,3],[1,3,2],[2,3,1],[2,1,3],[3,1,2],[3,2,1]]


next up previous contents index
suivant: Récupérer et installer un monter: Les permutations précédent: Les permutations circulaires   Table des matières   Index
Documentation de giac écrite par Renée De Graeve