费雪耶茨洗牌
也被称为 Knuth shuffle 和 Durstenfeld-Fisher-Yates shuffle。这个 shuffle 采用了一系列 n
元素并将其洗牌。该算法是真正随机的,因为在混洗之后,阵列的每个排列都是同样可能的。
在 java 中:
public static void shuffle(E[] deck) {
//From the end, swap each card with a random card from the unswapped portion.
for(int i = deck.length - 1; i > 0; i--)
{
//Pick an element from [0,i], inclusive.
int chosenCard = (int) (Math.random() * (i + 1));
E temp = deck[i];
deck[i] = deck[chosenCard];
deck[chosenCard] = temp;
}
}
请注意:替换元素必须来自[0,i]包含而不是[0,i]独占:否则,元素保留到位的数组的排列是不可能的,这不是真正随机的。
假设假设随机数采用 O(1)
生成,则算法就地运行并占用 O(n)
时间和空间。以这种方式混洗的数组可用于检索每个元素的 O(1)
摊销时间中的非重复元素。
E[] deck;
int drawIndex;
//Elements are taken from an index that advances.
public E drawUniqueCard()
{
//Once all cards have been drawn, reshuffle the deck and draw from the top.
if(drawIndex == deck.length)
{
shuffle(deck);
drawIndex = 0;
}
//Pull the next card off the deck.
return deck[drawIndex++];
}