偶尔看到有人在讨论如何生成不重复的随机数系列(洗牌算法),发现他们用的方法复杂度十分高,要抛大量的随机数,因此把我以前用的洗牌算法也拿出来秀秀。
假设需要生成 1~54 的随机数,那么把 1~54 放入“数组”,抛 0~53 的随机数,把指定序号的牌,和最后一张牌交换。
下一步,抛 0~52 的随机数……
重复 53 次就可以洗完牌,只需要53个随机数,53次交换,复杂度相当低,可以在常数时间内完成。
演示代码如下:
int main()
{
srand((unsigned int)time(NULL));
const int count = 54;
int cards[count];
// 初始化未洗牌数组
for (int i = 0; i < count; ++i)
cards[i] = i + 1;
for (int i = count; i > 0; --i) {
int index = rand() % i;
// 交换随机位置和最后未交换过的牌
int x = cards[index];
cards[index] = cards[i - 1];
cards[i - 1] = x;
}
std::copy(cards, cards+count, std::ostream_iterator<int>(std::cout, " "));
return 0;
}