随机洗牌算法
来源:互联网 发布:windows版icloud 编辑:程序博客网 时间:2024/05/18 08:54
扑克牌洗牌是我们生活中比较喜欢玩的一个游戏。那么我们有没有什么办法自己设计一个扑克牌洗牌的方法呢?在c运行库当中有一个随机函数rand,它可以生成0~32767之间的任意数。那么有没有可能利用这么一个函数对我们扑克牌进行随即洗牌呢?
在这里我抛砖引玉一下,谈一谈自己目前已经看到的两个算法。欢迎朋友们谈一谈其他的方法。
(1)全局洗牌法
步骤如下所示:
a)首先生成一个数组,大小为54,初始化为1~54
b)按照索引1到54,逐步对每一张索引牌进行洗牌,首先生成一个余数 value = rand %54,那么我们的索引牌就和这个余数牌进行交换处理
c)等多索引到54结束后,一副牌就洗好了
代码如下所示:
- void get_rand_number(int array[], int length)
- {
- int index;
- int value;
- int median;
- if(NULL == array || 0 == length)
- return ;
- /* 每次发牌的时候任意分配待交换的数据 */
- for(index = 0; index < length; index ++){
- value = rand() % length;
- median = array[index];
- array[index] = array[value];
- array[value] = median;
- }
- }
上面的算法非常简单,但是有一个问题,我们发现每次洗牌之后原来洗好的牌都会进行二次操作,个人觉得有点说不过去,所以不妨加以改进:
a)同样,首先我们生成一个大小为54的数组,数组排列为1~54
b)索引牌从1开始,到54结束。这一次索引牌只和剩下还没有洗的牌进行交换, value = index + rand() %(54 - index)
c)等到所有的索引牌都洗好之后,一副牌就弄好了
代码如下所示:
- void get_rand_number(int array[], int length)
- {
- int index;
- int value;
- int median;
- if(NULL == array || 0 == length)
- return ;
- /* 发牌的时候对于已经分配的数据不再修改 */
- for(index = 0; index < length; index ++){
- value = index + rand() % (length - index);
- median = array[index];
- array[index] = array[value];
- array[value] = median;
- }
- }
最朴素的做法
对于这个问题我们从最朴素的解法谈起。每次随机选出一个没有被选过的数放到一个队列中,如果随机出来的数已经被选过,那么继续随机直到遇到一个没有被选过的数放入到队列中;重复这样子操作直到所有的数都被选择出来。
我们看看这样子作为什么是对的。首先选第一个数的时候有n个数可选,第2个数的时候有(n-1)个数可选,-----这样子看来我们的排列有n*(n-1)*(n-1)*-----*1种,也就是我们最后选出来的排列是n!的排列中的任意一个,这样子显然是符合随机洗牌的要求的。
但是我们反观该方法的时间复杂度,由于我们每次随机选出一个数都有可能是之前选过的数,需要进行再次随机,因此对选出一个数的随机平均情况下需要随机O(n)次,因此该方法的时间复杂度是O(n^2)的。而且另外还要记一个队列,甚至需要记一个数是否被选出来过,因此该最朴素的做法的时间和空间复杂度都不是最好的,我们需要考虑更好的办法。
经典的洗牌算法
很多面试官需要你会的洗牌算法当然是经典的洗牌算法,也就是我们考虑如何对上面的洗牌算法进行优化。
我们考虑,当一个数被选之后,我们是没有必要在下一次随机的时候再考虑它的,因此,我们每次只从可选的数的集合中进行随机,也就不用考虑是否会碰到已经选过的数了,这样子直接将算法的复杂度降了一个数量级。
- void MySwap(int &x, int &y)
- {
- int temp = x;
- x = y;
- y = temp;
- }
- void Shuffle(int n)
- {
- for(int i=n-1; i>=1; i--)
- {
- MySwap(num[i], num[rand()%(i+1)]);
- }
- }
参照上面的代码,我们可以看到,我们每次都是随机的从没有选的数中选择一个,该洗牌算法的时间复杂度为O(n),空间复杂度为O(0)。正确性如上面一样证明
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- php随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- 随机洗牌算法
- [算法] 洗牌算法&随机算法
- 随机洗牌算法和随机选择算法
- 随机取样和洗牌算法
- 等概率随机洗牌算法
- 随机问题之--洗牌算法
- 一个最简单的google map页面
- 条件控制语句
- 数据库事物
- php 分页 【3种形式】
- 软件设计与结构化设计方法
- 随机洗牌算法
- 菜鸟调错(三)——Jboss与jdk版本不兼容导致WebService调用出错
- 聚集索引与非聚集索引【待理解】
- 一定不能再让CSDN博客长草了。
- 【存储管理】物理页面的使用和周转
- MOUNT挂载设备
- 在iOS项目中使用FMDataBase
- VC中tab控件的使用
- 基于OSEck系统的TI C66x DSP进程间的三种通信机制