BifaceMcLeOD a écrit :
Et comme Sun est ton ami, le JDK inclut déjà en standard deux méthodes shuffle() (dans la classe java.util.Collections) qui implémentent déjà ce type d'algorithmes.
|
Avec un petit exemple (simplifié au maximum ici) si on ne comprends toujours pas que shuffle() signifie mélanger (comme on mélange un tas de cartes):
Code :
- import java.util.Random;
- // (...)
- int cartes[998];
- // initialisation des cartes dans un paquet trié de 1 à 998 dans l’ordre ; mettez-y les valeurs uniques que vous voulez avoir :
- for (int i = 0; i < 998; i++) cartes[i] = i + 1;
- // on bat les cartes (shuffle en anglais) :
- Random generateur = new Random(); // il nous faut un objet générateur aléatoire
- for (int i = 1; i < 998; i++) { // note : on ignore la première carte qui ne peut être mélangée toute seule.
- int alea = generateur.nextInt(i); //tirage d’une position entre 0 et (i - i) dans le tas de cartes déjà mélangé;
- int carte = cartes[alea]; // on extrait une carte du début du paquet déjà mélangé
- // on échange :
- cartes[alea] = cartes[i]; // on place à cette position aléatoire du paquet mélangé la nouvelle carte venant du paquet trié
- cartes[i] = carte; // la carte extraite du paquet mélangé est placée au dessus de ce paquet
- }
|
Méthode simple au comportement linéaire. On peut rebattre le paquet si on veut tout le paquet en refaisant la seconde boucle.
Pour décrire cette méthode: on part d'un paquet trié qu'on pose en entier sur une pile à droite, on tire la carte au dessus de cette pile et on extrait une carte au hasard de la pile de gauche (au départ vide), qu'on remplace par la carte qu'on vient de tirer du paquet de droite, cette dernière venant se replacer au dessus du paquet de gauche. Et on réitère jusqu'à ce qu'il n'y ait plus de carte dans la pile de droite.
Cela ne demance aucune insertion, juste un échange local.
On montre facilement que le paquet obtenu est mélangé aléatoirement si chacun des tirages aléatoire dans le paquet de gauche est uniforme (les probabilités de tirage de chacun des nombres de 0 à N-1 ne sont pas équitables pour toutes les valeurs de N, malgré le soin apporté dans le générateur utilisé, cependant ce générateur utilise une graine sur 48 bits qui suffit largement pour réaliser de bons tirages pour toutes les valeurs de N jusqu'à 32 bits, et ici on est très loin de cette limite, N valant au maximum 998 ci-dessus).
Cependant Random.nextInt() n'est pas parfaitement uniforme (car il utilise un générateur pseudo-aléatoire et non un vrai générateur aléatoire de "qualité militaire" ), il est donc possible voire utile de rebattre une seconde fois (en coupant éventuellement le paquet avant, ce que ne fait pas la méthode shuffle() du JRE, mais rien n'interdit de l'employer une seconde fois).
L'équivalent de "couper le paquet" avant de rebattre, c'est ici de remplacer le générateur aléatoire par une nouvelle instance (car chaque générateur instancié par new Random() génère une suite à priori différente, puisque le générateur utilisera une autre "graine", ce qui n'est pas le cas pour le générateur de la classe Math qui est unique et instancié en interne).
Cependant j'ai oublié de dire qu'il y avait une méthode shuffle() aussi pour les tableaux, pas seulement les connections.
Voir dans la classe java.util.Arrays... qui permet de mélanger des tableaux de nombres ou d'objets, ce que ne fait pas la méthode shuffle() dans java.util.Collection puisque les tableaux natifs Java ne sont pas des collections.
Message édité par verdy_p le 01-02-2008 à 17:42:22