FisherYates shuffle 基本思想(Knuth shuffle ):
Pour mélanger un tableau a de n éléments (indices 0..n-1) :
pour i de n − 1 jusqu'à 1 faire
j ← entier aléatoire avec 0 ≤ j ≤ i
échanger a[j] et a[i]
Fonctionnement du JDK :
/**
* Déplace chaque élément de la liste vers une nouvelle position aléatoire dans la liste
* en utilisant le générateur de nombres aléatoires spécifié.
*
* Liste @param
* la liste à mélanger
* @param aléatoire
* le générateur de nombres aléatoires
*
* @throwsUnsupportedOperationException
* lorsque le remplacement d'un élément dans la liste n'est pas pris en charge
*/
@SuppressWarnings("non coché")
public static void shuffle (List<?> list, Random random) {
if (!(liste des instances de RandomAccess)) {
Tableau Object[] = list.toArray();
pour (int i = array.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
si (indice < 0) {
indice = -indice ;
}
Objet temp = tableau[i];
tableau[i] = tableau[index];
tableau[index] = temp;
}
int je = 0;
ListIterator<Object> it = (ListIterator<Object>) liste
.listIterator();
tandis que (it.hasNext()) {
it.next();
it.set(array[i++]);
}
} autre {
List<Object> rawList = (List<Object>) liste ;
pour (int i = rawList.size() - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
si (indice < 0) {
indice = -indice ;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
}
public static void main (final String args[]) {
Objet changeTemp ;
List<Integer> numList = new ArrayList<Integer>();
List<Integer> firstList = new ArrayList<Integer>();
List<Integer> secondList = new ArrayList<Integer>();
List<Integer>thirdList = new ArrayList<Integer>();
List<Integer> fourthList = new ArrayList<Integer>();
pour (int je = 1; je <= 100000; i++) {
numList.add(i);
firstList.add(i);
secondeList.add(i);
ThirdList.add(i);
quatrièmeListe.ajouter(i);
}
// premier mélange, utilisez changeTemp
getStartTime();
int randInt = 0;
for (int i = 0, length = firstList.size(); i < length; i++) {
randInt = getRandom(i, firstList.size());
changeTemp = firstList.get(i);
firstList.set(i, firstList.get(randInt));
firstList.set(randInt, javaShuffle.temp);
}
getEndTime("première exécution aléatoire ");
// deuxième lecture aléatoire, liste d'échange
getStartTime();
for (int i = 0, length = secondList.size(); i < length; i++) {
randInt = getRandom(i, secondList.size());
secondList.set(i, secondList.set(randInt, secondList.get(i)));
}
getEndTime("deuxième durée d'exécution aléatoire");
// troisième mélange, changement génère un entier aléatoire
getStartTime();
Object[] tempArray = ThirdList.toArray();
Rand aléatoire = new Random();
entier j = 0 ;
pour (int i = tempArray.length - 1; i > 0; i--) {
j = rand.nextInt(i + 1);
ThirdList.set(i, ThirdList.set(j, ThirdList.get(i)));
}
getEndTime("troisième temps d'exécution aléatoire ");
// quatrième shuffle, simule Java Shuffle
getStartTime();
Aléatoire aléatoire = nouveau Aléatoire();
if (!(quatrième instance de liste de RandomAccess)) {
Tableau Objet[] = quatrièmeListe.toArray();
pour (int i = array.length - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
si (indice < 0) {
indice = -indice ;
}
Objet temp = tableau[i];
tableau[i] = tableau[index];
tableau[index] = temp;
}
int je = 0;
ListIterator<Integer> it = (ListIterator<Integer>) quarterList.listIterator();
tandis que (it.hasNext()) {
it.next();
it.set((Integer) array[i++]);
}
} autre {
List<Integer> rawList = (List<Integer>) FourthList ;
pour (int i = rawList.size() - 1; i > 0; i--) {
int index = random.nextInt(i + 1);
si (indice < 0) {
indice = -indice ;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
getEndTime("quatrième durée d'exécution aléatoire");
// java aléatoire
getStartTime();
Collections.shuffle(numList);
getEndTime("Durée d'exécution Java Shuffle ");
}
échange de vide statique public (int a, int b) {
javaShuffle.temp = a;
une = b;
b = javaShuffle.temp;
}
public static int getRandom (final int bas, final int haut) {
return (int) (Math.random() * (haut - bas) + bas);
}
public static void getStartTime() {
javaShuffle.start = System.nanoTime();
}
public static void getEndTime (final String s) {
javaShuffle.end = System.nanoTime();
System.out.println(s + ": " + (javaShuffle.end - javaShuffle.start) + "ns");
}
}
如果数值较小,例如100000级别,则输出大概是:
Temps de première lecture aléatoire : 85029499ns
durée de la deuxième lecture aléatoire : 80909474ns
Temps de troisième lecture aléatoire : 71543926ns
durée de la quatrième lecture aléatoire : 76520595ns
Temps d'exécution de Java Shuffle : 61027643ns
durée de la première lecture aléatoire : 82326239ns
durée de la deuxième lecture aléatoire : 78575611ns
Temps de troisième lecture aléatoire : 95009632ns
durée de la quatrième lecture aléatoire : 105946897ns
Temps d'exécution de Java Shuffle : 90849302ns
Temps de première lecture aléatoire : 84539840ns
durée de la deuxième lecture aléatoire : 85965575ns
Temps de troisième lecture aléatoire : 101814998ns
durée de la quatrième lecture aléatoire : 113309672ns
Temps d'exécution de Java Shuffle : 35089693ns
durée de la première lecture aléatoire : 87679863ns
durée de la deuxième lecture aléatoire : 79991814ns
Temps de troisième lecture aléatoire : 73720515ns
durée de la quatrième lecture aléatoire : 78353061ns
Temps d'exécution de Java Shuffle : 64146465ns
Temps de première lecture aléatoire : 84314386ns
durée de la deuxième lecture aléatoire : 80074803ns
Temps de troisième lecture aléatoire : 74001283ns
durée de la quatrième lecture aléatoire : 79931321ns
Temps d'exécution de Java Shuffle : 86427540ns
Temps de première lecture aléatoire : 84315523ns
durée de la deuxième lecture aléatoire : 81468386ns
Temps de troisième lecture aléatoire : 75052284ns
durée de la quatrième lecture aléatoire : 79461407ns
Temps d'exécution de Java Shuffle : 66607729ns
如果是10000000级别,大概如下:
durée de la première lecture aléatoire : 2115703288ns
durée de la deuxième lecture aléatoire : 3114045871ns
Temps d'exécution du troisième mélange : 4664426798ns
Durée de la quatrième lecture aléatoire : 2962686695ns
Temps d'exécution java shuffle : 3246883026ns Premier temps d'exécution aléatoire : 2165398466ns
durée de la deuxième lecture aléatoire : 3129558913ns
Temps d'exécution du troisième mélange : 4147859664ns
durée de la quatrième lecture aléatoire : 2911849942ns
Temps d'exécution java shuffle : 4311703487ns Premier temps d'exécution aléatoire : 2227462247ns
durée de la deuxième lecture aléatoire : 3279548770ns
Temps d'exécution du troisième mélange : 4704344954ns
durée de la quatrième lecture aléatoire : 2942635980ns
Temps d'exécution java shuffle : 3933172427ns Premier temps d'exécution aléatoire : 2200158789ns
durée de la deuxième lecture aléatoire : 3172666791ns
Temps d'exécution du troisième mélange : 4715631517ns
durée de la quatrième lecture aléatoire : 2950817535ns
Temps d'exécution java shuffle : 3387417676ns Premier temps d'exécution aléatoire : 2201124449ns
durée de la deuxième lecture aléatoire : 3203823874ns
Temps de troisième lecture aléatoire : 4179926278ns
durée de la quatrième lecture aléatoire : 2913690411ns
Temps d'exécution java shuffle : 3571313813ns Premier temps d'exécution aléatoire : 2163053190ns
durée de la deuxième lecture aléatoire : 3073889926ns
Temps d'exécution du troisième mélange : 4493831518ns
durée de la quatrième lecture aléatoire : 2852713887ns
Temps d'exécution de Java Shuffle : 3773602415ns
可以看出,第一种方法速度最快,而第四种最慢。java自带 shuffle速度也不理想。
在进行大数据处理的时候,如果使用java库效率较低时,可以考虑使用其他方式。