洗牌算法是我们常见的随机问题,在玩游戏、随机排序时经常会碰到。它可以抽象成这样:得到一个M以内的所有自然数的随机顺序数组。
洗牌算法大多都是建立在随机数的基础上的,现在介绍几种随机数基础上的随机洗牌算法:
(1)第一种可以简单描述成:随机抽牌,放在另一组;再次抽取,抽到空牌则重复抽。抽到空牌则重新抽的话,越到后面抽到空牌的几率就越大,所以显然是不合理的。我们可以进一步优化:拍抽走后,原牌变少,我们把抽走的牌之后的牌往前移一位,来填补空牌的空缺。代码如下:
vector<int> shuffle_pick_1(size_t m) {
vector<int> vec1;
//生成m张牌
for(size_t i=0; i<m ; i++)
vec1.push_back(i);
vector<int> vec2;
for(size_t i=m; i>0; i--){
int rmd = floor(random()*i);
vec2.push_back(vec1[rmd]);
vec1.erase(vec1.begin()+rmd); //从原来的牌中删除空牌
}
return vec2;
}
这个也明显有问题,因为数组如果很大的话,删除中间的某个元素,会导致后面的排队向前走一步,这是一个很耗时的动作。
回想一下“我们为什么要删除那个元素?”目的就是为了不产生空牌。
除了删除那个元素之外,我们是不是还有其它方式来去除空牌?
—-有的,我们把最后一张未抽的牌放在那个抽走的位置上就可以了。
所以,这个思路我们可以优化成这样:
未完待续。。。