斗地主游戏之洗牌算法

  斗地主之类的游戏大家都玩过,有没有想过,游戏是如何给我们发牌的呢?

  我们先将问题做一下抽象:我们将扑克牌抽象为数字,那么洗牌的问题就转化为

给定一个长度为54的整型数列,请将其顺序随机打乱,保证每个数出现在任意一个位置的概率相同。

朴素的想法——抽牌

每次随机从牌堆中选一个位置抽牌,如果该位置的牌已被抽走,则继续随机选取位置,直到将所有牌抽完。

  显然,这种做法时间复杂度很高。那么不妨稍微优化下。

每次随机从牌堆中选一个位置抽牌,然后将该位置后面的牌依次向前移动一个位置,下一次从新牌堆(数量-1)中抽取,循环到抽完所有牌为止。

  这样也能完成要求,单这样的做法,对于数据规模比较小的数据可以接受,但数据量一旦变大,反而不如不优化的算法效率高。我们还得继续想办法优化。

每次随机从牌堆中选一个位置抽牌,然后将最后一张牌移动到被选择的位置,下一次从新牌堆(数量-1)中抽取,循环到抽完所有牌为止。

  这样优化完以后,时间复杂度降低到了O(N),应该能满足要求了。

经典的洗牌算法——交换

  上面的算法需要额外的辅助空间,那么能不能就地洗牌呢?答案当然是可以的。

还是每次随机一个位置,然后将该位置上的牌与 i 位置上的牌交换,直到 i 遍历玩所有位置为止。

 1 void MySwap(int &x, int &y)  
 2 {  
 3     int temp = x;  
 4     x = y;  
 5     y = temp;  
 6 }  
 7   
 8 void Shuffle(int n)  
 9 {  
10     for(int i=n-1; i>=1; i--)  
11     {  
12         MySwap(num[i], num[rand()%(i+1)]);  
13     }  
14 }  
洗牌算法

  该洗牌算法的时间复杂度为O(N),空间复杂度为O(N)。

 

posted @ 2016-12-20 12:08  feelingscoder  阅读(2297)  评论(0编辑  收藏  举报