偶爾有用的替代洗牌方法是使用可下標集容器。在每一步中,選擇一個隨機數0 < = n < count。從集合中提取第n個項目。
主要問題是典型的容器無法有效地處理這個問題。我已經將它用於位矢量,但只有在可能的最大成員相當小的情況下才能正常工作,這是由於要找到第n個設置位所需的位向量的線性掃描。
99%的時間,最好的方法是洗牌,如其他人所建議的。
編輯
我錯過了一個事實,即一個簡單的數組是一個很好的「設置」數據結構 - 不要問我爲什麼,我曾經使用過它。 「技巧」是你不關心數組中的項是否被排序。在每一步中,您隨機選擇一個並提取它。要填充空槽(不必將平均一半的項目移動一步),只需將當前最終項目在恆定時間內移動到空槽中,然後將數組的大小減小一。
例如...
class remaining_items_queue
{
private:
std::vector<int> m_Items;
public:
...
bool Extract (int &p_Item); // return false if items already exhausted
};
bool remaining_items_queue::Extract (int &p_Item)
{
if (m_Items.size() == 0) return false;
int l_Random = Random_Num (m_Items.size());
// Random_Num written to give 0 <= result < parameter
p_Item = m_Items [l_Random];
m_Items [l_Random] = m_Items.back();
m_Items.pop_back();
}
訣竅是得到一個隨機數發生器,讓(具有相當均勻的分佈)數取值範圍爲0到n-1,其中n每次都是潛在的不同。大多數標準隨機發生器給出一個固定的範圍雖然下面DOES NOT給均勻分佈,它往往是不夠好......
int Random_Num (int p)
{
return (std::rand() % p);
}
的std ::蘭特範圍爲0 < = X < RAND_MAX,其中RAND_MAX是實現定義返回隨機值。
值得指出的是,「標準」洗牌你提的是費雪耶茨-Durstenfeld算法:http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm – LukeH 2010-02-17 13:14:17