Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
permutations [2010/01/09 08:47] tyrtamos |
permutations [2010/01/09 11:27] tyrtamos |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
====== Permutations ====== | ====== Permutations ====== | ||
+ | |||
+ | ===== Objectif ===== | ||
+ | |||
+ | Exemple: soit une liste d' | ||
+ | |||
+ | * on veut savoir les présenter de toutes les façons possibles: %%[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]%%, | ||
+ | |||
+ | * en tenant compte si nécessaire des répétitions (ex: [1,2,2] | ||
+ | |||
+ | * et on veut savoir combien il y en a. | ||
+ | |||
+ | \\ | ||
+ | Référence externe pour la définition: | ||
+ | |||
+ | ===== Calcul du nombre de permutations ===== | ||
+ | |||
+ | ==== Nombre de permutations sans répétition ==== | ||
+ | |||
+ | Dans l' | ||
+ | |||
+ | On va donc reprendre le code de la factorielle dans sa version non récursive: | ||
+ | |||
+ | <code python> | ||
+ | def permut(n): | ||
+ | """ | ||
+ | x = 1 | ||
+ | for i in xrange(2, n+1): | ||
+ | x *= i | ||
+ | return x | ||
+ | </ | ||
+ | |||
+ | Exemple d' | ||
+ | |||
+ | <code python> | ||
+ | print permut(3) | ||
+ | 6 | ||
+ | </ | ||
+ | |||
+ | ==== Nombre de permutations avec répétition ==== | ||
+ | |||
+ | Là, on a un objet plus complexe, composés d' | ||
+ | |||
+ | Par exemple: [1, | ||
+ | |||
+ | Ainsi, il y aura permut(8)=40320 façons de présenter cette liste, mais certaines seront identiques! | ||
+ | |||
+ | On veut donc calculer ici le nombre de permutations //en ne comptant qu'une seule fois les permutations identiques// | ||
+ | |||
+ | Il suffit de diviser le nombre total de permutations par chacune des factorielles des répétitions. | ||
+ | |||
+ | Pour reprendre l' | ||
+ | |||
+ | Voilà le code qui fait ça. Pour le lancer, on met comme paramètre le nombre d' | ||
+ | |||
+ | <code python> | ||
+ | def permut(n, r=[]): | ||
+ | """ | ||
+ | r est la liste des éventuelles répétitions rencontrées dans les n objets | ||
+ | | ||
+ | """ | ||
+ | x = 1 | ||
+ | for i in xrange(2, n+1): | ||
+ | x *= i | ||
+ | for m in r: | ||
+ | y = 1 | ||
+ | for i in xrange(2, m+1): | ||
+ | y *= i | ||
+ | x //= y | ||
+ | return x | ||
+ | </ | ||
+ | |||
+ | Exemple: | ||
+ | |||
+ | <code python> | ||
+ | # objet de 8 éléments avec le 2 mis 2 fois et le 5 mis 3 fois | ||
+ | seq = [1, | ||
+ | |||
+ | # nombre total de permutation sans répétition | ||
+ | print permut(len(seq)) | ||
+ | 40320 | ||
+ | |||
+ | # nombre de permutations avec répétitions | ||
+ | # (= en ne comptant qu'une seule fois les permutations identiques) | ||
+ | print permut(len(seq), | ||
+ | 3360 | ||
+ | </ | ||
+ | |||
+ | Bien entendu, on peut calculer automatiquement la liste des répétitions des objets dans la liste des objets. | ||
+ | |||
+ | Par exemple comme suit (code très auto-commenté!): | ||
+ | |||
+ | <code python> | ||
+ | def repetelem(seq): | ||
+ | """ | ||
+ | r = [] # pour enregistrer les éléments déjà traités | ||
+ | d = [] # pour enregistrer le nombre de répétitions > 1 des éléments | ||
+ | for elem in seq: | ||
+ | if (elem not in r): # si l' | ||
+ | r.append(elem) | ||
+ | x = seq.count(elem) | ||
+ | if x> | ||
+ | d.append(x) | ||
+ | return d # on renvoie la liste des répétitions > 1 rencontrées | ||
+ | </ | ||
+ | |||
+ | Exemple d' | ||
+ | |||
+ | <code python> | ||
+ | seq = [1, | ||
+ | |||
+ | print repetelem(seq) | ||
+ | [2, 3, 6] | ||
+ | |||
+ | print permut(len(seq)) | ||
+ | 87178291200 | ||
+ | |||
+ | print permut(len(seq), | ||
+ | 10090080 | ||
+ | </ | ||
+ | |||
+ | S'il n'y a qu'une seule de ces 2 fonctions permut() à retenir (sans ou avec répétition), | ||
+ | |||
+ | * s'il n'y a qu'un seul argument, c'est qu'on n'a pas de répétition (ou qu'on n'en tient pas compte). | ||
+ | |||
+ | * dans le cas contraire, il suffit d' | ||
+ | |||
+ | ===== Liste des permutations de chaînes de caractères présentées dans une liste ===== | ||
+ | |||
+ | On sait maintenant calculer le **nombre** de permutations, | ||
+ | |||
+ | Par exemple: trouver toutes les permutations possibles de [1, 2, 3], c'est à dire: [1, 2, 3], [1, 3, 2], [2, 3, 1], [2, 1, 3], [3, 1, 2], [3, 2, 1] | ||
+ | |||
+ | Ça pourrait, bien sûr, être une liste de n' | ||
+ | |||
+ | Sont présentés ci-dessous un code non-récursif (que je conseille) et un code récursif. Ils sont basés sur le même principe: des rotations des éléments qui se trouvent entre l' | ||
+ | |||
+ | Par exemple pour seq=[1, | ||
+ | |||
+ | * pour k=0, on aura les rotations: [1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3] | ||
+ | |||
+ | * pour k=1, on aura les rotations: [1,2,3,4], [1,3,4,2], [1,4,2,3] | ||
+ | |||
+ | * pour k=2, on aura les rotations: [1,2,3,4], [1,2,4,3] | ||
+ | |||
+ | * pour k=3, c'est à dire pour k=len(seq)-1, | ||
+ | |||
+ | Pour chaque k, il y a len(seq)-k rotations en tout (c'est à dire len(seq)-k-1 en plus du seq initial) | ||
+ | |||
+ | Pour faire une rotation à partir de l' | ||
+ | |||
+ | \\ | ||
+ | Bon. Dans vos essais, soyez raisonnables: | ||
+ | |||
+ | ==== Code non récursif ==== | ||
+ | |||
+ | Le code non-récursif est ici assez concis et très rapide (2 à 3 fois plus que le code récursif). | ||
+ | |||
+ | Voilà le code: | ||
+ | |||
+ | <code python> | ||
+ | def permutliste(seq, | ||
+ | """ | ||
+ | si er=True: élimination des répétitions quand seq en a (ex: [1,2,2] | ||
+ | """ | ||
+ | p = [seq] | ||
+ | n = len(seq) | ||
+ | for k in xrange(0, | ||
+ | for i in xrange(0, len(p)): | ||
+ | z = p[i][:] | ||
+ | for c in xrange(0, | ||
+ | z.append(z.pop(k)) | ||
+ | if er==False or (z not in p): | ||
+ | p.append(z[: | ||
+ | return p | ||
+ | </ | ||
+ | |||
+ | On peut améliorer sa présentation avec un tri (avec p.sort() ou sorted(p) par ex.). | ||
+ | |||
+ | On a tenu compte d'un 2ème argument ici pour éviter les répétitions. En effet, quand la liste initiale seq contient des éléments qui se répètent, le résultat contiendra plusieurs listes identiques. Pour que ces listes identiques ne soient comptées qu'une seule fois, il suffit d' | ||
+ | |||
+ | Exemple d' | ||
+ | |||
+ | <code python> | ||
+ | seq = [1,2,3] | ||
+ | print permutliste(seq) | ||
+ | [[1, 2, 3], [1, 3, 2], [2, 3, 1], [2, 1, 3], [3, 1, 2], [3, 2, 1]] | ||
+ | |||
+ | seq = [1,2,2] | ||
+ | print permutliste(seq) | ||
+ | [[1, 2, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 1, 2], [2, 2, 1]] | ||
+ | |||
+ | seq = [1,2,2] | ||
+ | print permutliste(seq, | ||
+ | [[1, 2, 2], [2, 2, 1], [2, 1, 2]] | ||
+ | </ | ||
+ | |||
+ | |||
+ | ==== Code récursif ==== | ||
+ | |||
+ | Voilà le code récursif: | ||
+ | |||
+ | <code python> | ||
+ | def permutliste(seq, | ||
+ | """ | ||
+ | si er=True: élimination des répétitions quand seq en a (ex: [1,2,2] | ||
+ | """ | ||
+ | n = len(seq) | ||
+ | if k == n-1: | ||
+ | return [] | ||
+ | p = [] | ||
+ | z = seq[:] | ||
+ | for c in xrange(0, n-k): | ||
+ | if er==False or (z not in p): | ||
+ | p.append(z[: | ||
+ | p.extend(permutliste(z, | ||
+ | z.append(z.pop(k)) | ||
+ | return p | ||
+ | </ | ||
+ | |||
+ | On ne donne jamais le 3ème argument k qui n'est utilisé que comme variable interne. | ||
+ | |||
+ | Au lancement de la fonction permutliste([1, | ||
+ | |||
+ | Ce code donne bien entendu les mêmes résultats que le code non-récursif. | ||
+ | |||
+ | Si vous voulez un résultat plus " | ||
+ | |||
+ | Et pour éviter les répétitions au cas où des éléments se répètent dans la liste seq, on ajoute simplement l' | ||
+ | |||
+ | |||
+ | ===== Liste des permutations des caractères d'une chaîne de caractères ===== | ||
+ | |||
+ | Même principe que précédemment, | ||
+ | |||
+ | Utilisation possible (entre autres): recherche d' | ||
+ | |||
+ | La solution de codage utilise l'une des fonctions précédentes qui traite les listes (Python est vraiment doué pour manipuler des listes!): | ||
+ | |||
+ | <code python> | ||
+ | def permutchaine(ch, | ||
+ | """ | ||
+ | avec er=True pour éviter les répétitions quand ch en a (ex: ' | ||
+ | """ | ||
+ | return ['' | ||
+ | </ | ||
+ | |||
+ | <code python> | ||
+ | # exemples d' | ||
+ | print permutchaine(" | ||
+ | </ | ||
+ | |||
+ | Si vous voulez que la chaîne résultat soit rangée selon l' | ||
+ | |||
+ | <code python> | ||
+ | R=permutchaine(" | ||
+ | print R # affiche: [' | ||
+ | R.sort() | ||
+ | print R # affiche: [' | ||
+ | R.reverse() | ||
+ | print R # affiche: [' | ||
+ | </ | ||
+ | |||
+ | Il y a une utilisation très intéressante de permutchaine(): | ||
+ | |||
+ | Par exemple: | ||
+ | |||
+ | <code python> | ||
+ | print sorted(permutchaine(' | ||
+ | </ | ||
+ | |||
+ | Ce qui affichera (en une seule ligne): | ||
+ | |||
+ | <code python>[ | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ]</ | ||
+ | |||
+ | |||
+ | \\ | ||
+ | Amusez-vous bien! | ||
+ | |||
+ | |||