FisherYates shuffle 基本思想(Knuth shuffle ):
Para embaralhar uma matriz a de n elementos (índices 0..n-1):
para i de n − 1 até 1 faça
j ← inteiro aleatório com 0 ≤ j ≤ i
troque a[j] e a[i]
JDK源代码如下:
/**
* Move cada elemento da lista para uma nova posição aleatória na lista
* usando o gerador de números aleatórios especificado.
*
* @param lista
* a lista para embaralhar
* @param aleatório
* o gerador de números aleatórios
*
* @throwsUnsupportedOperationException
* ao substituir um elemento na Lista não é suportado
*/
@SuppressWarnings("desmarcado")
public static void shuffle(Lista<?> lista, Aleatório aleatório) {
if (!(listar instância de RandomAccess)) {
Objeto[] array = list.toArray();
for (int i = array.length - 1; i > 0; i--) {
índice interno = random.nextInt(i + 1);
se (índice <0) {
índice = -índice;
}
Temperatura do objeto = array[i];
matriz[i] = matriz[índice];
matriz[índice] = temp;
}
int eu = 0;
ListIterator<Object> it = (ListIterator<Object>) lista
.listIterator();
enquanto (it.hasNext()) {
it.next();
it.set(matriz[i++]);
}
} outro {
Lista<Objeto> rawList = (Lista<Objeto>) lista;
for (int i = rawList.size() - 1; i > 0; i--) {
índice interno = random.nextInt(i + 1);
se (índice <0) {
índice = -índice;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
}
public static void main(string final args[]) {
Mudança de objetoTemp;
List<Integer> numList = new ArrayList<Integer>();
List<Integer> firstList = new ArrayList<Integer>();
List<Integer> secondList = new ArrayList<Integer>();
List<Integer> terceiraLista = new ArrayList<Integer>();
List<Integer> quartaList = new ArrayList<Integer>();
for (int i = 1; i <= 100000; i++) {
numList.add(i);
primeiraLista.add(i);
segundaLista.add(i);
terceiraLista.add(i);
quartaLista.add(i);
}
// primeiro embaralhamento, use changeTemp
getStartTime();
int randInt = 0;
for (int i = 0, comprimento = firstList.size(); i < comprimento; i++) {
randInt = getRandom(i, firstList.size());
changeTemp = firstList.get(i);
firstList.set(i, firstList.get(randInt));
firstList.set(randInt, javaShuffle.temp);
}
getEndTime("tempo de execução do primeiro embaralhamento");
// segundo embaralhamento, lista de troca
getStartTime();
for (int i = 0, comprimento = segundaLista.size(); i < comprimento; i++) {
randInt = getRandom(i, secondList.size());
secondList.set(i, secondList.set(randInt, secondList.get(i)));
}
getEndTime("segundo tempo de execução aleatória");
// terceiro embaralhamento, mudança gera int aleatório
getStartTime();
Object[] tempArray = terceiraList.toArray();
Rand aleatório = new Random();
int j = 0;
for (int i = tempArray.length - 1; i > 0; i--) {
j = rand.nextInt(i + 1);
terceiraLista.set(i, terceiraLista.set(j, terceiraLista.get(i)));
}
getEndTime("terceiro tempo de execução aleatória ");
// quarto shuffle, simula java shuffle
getStartTime();
Aleatório aleatório = new Aleatório();
if (!(fourthList instanceof RandomAccess)) {
Object[] array = quartaList.toArray();
for (int i = array.length - 1; i > 0; i--) {
índice interno = random.nextInt(i + 1);
se (índice <0) {
índice = -índice;
}
Temperatura do objeto = array[i];
matriz[i] = matriz[índice];
matriz[índice] = temp;
}
int eu = 0;
ListIterator<Integer> it = (ListIterator<Integer>) quartaList.listIterator();
enquanto (it.hasNext()) {
it.next();
it.set((Inteiro) array[i++]);
}
} outro {
List<Integer> rawList = (List<Integer>) quartaList;
for (int i = rawList.size() - 1; i > 0; i--) {
índice interno = random.nextInt(i + 1);
se (índice <0) {
índice = -índice;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
getEndTime("tempo de execução do quarto embaralhamento");
// embaralhamento java
getStartTime();
Coleções.shuffle(numList);
getEndTime("tempo de execução do Java Shuffle");
}
troca estática pública de void(int a, int b) {
javaShuffle.temp = a;
uma =b;
b = javaShuffle.temp;
}
public static int getRandom(final int baixo, final int alto) {
return (int) (Math.random() * (alto - baixo) + baixo);
}
public static void getStartTime() {
javaShuffle.start = System.nanoTime();
}
public static void getEndTime(string final s) {
javaShuffle.end = System.nanoTime();
System.out.println(s + ": " + (javaShuffle.end - javaShuffle.start) + "ns");
}
}
如果数值较小,例如100000级别,则输出大概是:
tempo de execução do primeiro embaralhamento: 85029499ns
tempo de execução do segundo shuffle: 80909474ns
tempo de execução do terceiro shuffle: 71543926ns
tempo de execução do quarto shuffle: 76520595ns
Tempo de execução do Java Shuffle: 61027643ns
tempo de execução do primeiro embaralhamento: 82326239ns
tempo de execução do segundo shuffle: 78575611ns
tempo de execução do terceiro shuffle: 95009632ns
tempo de execução do quarto shuffle: 105946897ns
Tempo de execução do Java Shuffle: 90849302ns
tempo de execução do primeiro embaralhamento: 84539840ns
tempo de execução do segundo shuffle: 85965575ns
tempo de execução do terceiro shuffle: 101814998ns
tempo de execução do quarto shuffle: 113309672ns
Tempo de execução do Java Shuffle: 35089693ns
tempo de execução do primeiro embaralhamento: 87679863ns
tempo de execução do segundo shuffle: 79991814ns
tempo de execução do terceiro shuffle: 73720515ns
tempo de execução do quarto shuffle: 78353061ns
Tempo de execução do Java Shuffle: 64146465ns
tempo de execução do primeiro embaralhamento: 84314386ns
tempo de execução do segundo shuffle: 80074803ns
tempo de execução do terceiro shuffle: 74001283ns
tempo de execução do quarto shuffle: 79931321ns
Tempo de execução do Java Shuffle: 86427540ns
tempo de execução do primeiro embaralhamento: 84315523ns
tempo de execução do segundo shuffle: 81468386ns
tempo de execução do terceiro shuffle: 75052284ns
tempo de execução do quarto shuffle: 79461407ns
Tempo de execução do Java Shuffle: 66607729ns
如果是10000000级别,大概如下:
tempo de execução do primeiro embaralhamento: 2115703288ns
tempo de execução do segundo shuffle: 3114045871ns
tempo de execução do terceiro embaralhamento: 4664426798ns
tempo de execução do quarto shuffle: 2962686695ns
tempo de execução do java shuffle: 3246883026ns tempo de execução do primeiro shuffle: 2165398466ns
tempo de execução do segundo shuffle: 3129558913ns
tempo de execução do terceiro embaralhamento: 4147859664ns
tempo de execução do quarto shuffle: 2911849942ns
tempo de execução do java shuffle: 4311703487ns tempo de execução do primeiro shuffle: 2227462247ns
tempo de execução do segundo shuffle: 3279548770ns
tempo de execução do terceiro embaralhamento: 4704344954ns
tempo de execução do quarto shuffle: 2942635980ns
tempo de execução do java shuffle: 3933172427ns tempo de execução do primeiro shuffle: 2200158789ns
tempo de execução do segundo shuffle: 3172666791ns
tempo de execução do terceiro embaralhamento: 4715631517ns
tempo de execução do quarto shuffle: 2950817535ns
tempo de execução do java shuffle: 3387417676ns tempo de execução do primeiro shuffle: 2201124449ns
tempo de execução do segundo shuffle: 3203823874ns
tempo de execução do terceiro embaralhamento: 4179926278ns
tempo de execução do quarto shuffle: 2913690411ns
tempo de execução do java shuffle: 3571313813ns primeiro tempo de execução do shuffle: 2163053190ns
tempo de execução do segundo shuffle: 3073889926ns
tempo de execução do terceiro embaralhamento: 4493831518ns
tempo de execução do quarto shuffle: 2852713887ns
Tempo de execução do Java Shuffle: 3773602415ns
可以看出,第一种方法速度最快,而第四种最慢。java自带 shuffle速度也不理想。
在进行大数据处理的时候,如果使用java库效率较低时,可以考虑使用其他方式。