洗牌算法

标签: 算法 棋牌 洗牌算法
13人阅读 评论(0) 收藏 举报
分类:

算法说明

洗牌算法实际上就是常见的随机问题。我们可以抽象理解为:得到一个M以内的所有自然数的随机顺序数组。

然而怎么样操作才是好的洗牌算法呢?我们通常认为得保证概率相等。即洗牌之后,如果能够保证每一个数出现在所有位置上的概率是相等的。


算法实现

算法一:随机抽取单张牌
  • 随机抽出一张牌
  • 检查这种牌是否被抽取过,如果已经被抽取过,则重新抽取,直到找到没有被抽取的牌;
  • 重复上述过程,直到所有的牌都被抽取到。

这种算法是比较符合大脑的直观思维,这种算法有两种形式:

  1. 每次随机抽取后,将抽取的牌拿出来,则此时剩余的牌为(N-1),这种算法避免了重复抽取,但是每次抽取一张牌后,都有一个删除操作,需要在原始数组中删除随机选中的牌(可使用Hashtable实现)

  2. 每次随机抽取后,将抽取的符合要求的牌做好标记,但并不删除;与1相比,省去了删除的操作,但增加了而外的存储标志为的空间,同时导致可每次可能会抽取之前抽过的牌

弊端:这种解决方案的时间/空间复杂度都不好。

算法二:随机抽取两张牌

每次随机抽出两张牌交换,交换一定次数后结束。

void shuffle(int* array, int len)  
{  
    const int suff_time = len;  

    for (int idx = 0; i < suff_time; i++)  
    {  
        int i = rand() % len;  
        int j = rand() % len;  

        int temp = array[i];  
        array[i] = array[j];  
        array[j] = temp;  
    }  
}

这是一个常见的洗牌算法。 但是如何确定一个合适的交换次数?

假设交换了m此,则某张牌始终没有被交换的概率为 (n-2)/n * (n-2)/n, … …* (n-2)/n = ((n-2)/n)^m;我们希望其概率小于摸个值,求出m的解.假设概率小于1/1000,对于n=52,m大概为176,实际上远远大于数组的长度.

算法三:Fisher–Yates shuffle算法

每次随机选取一个数,然后将该数与数组中最后(或最前)的元素相交换(如果随机选中的是最后/最前的元素,则相当于没有发生交换);然后缩小选取数组的范围,去掉最后的元素,即之前随机抽取出的数。重复上面的过程,直到剩余数组的大小为1,即只有一个元素时结束。

void shuffle(int* array, int len)  
{  
    int i = len;  
    int j = 0;  
    int temp= = 0;  

    if (i == 0)  
    {  
        return;  
    }  

    while (--i)  
    {  
        j = rand() % (i+1);  
        temp = array[i];  
        array[i] = array[j];  
        array[j] = temp;  
    }  
}  
查看评论

红孩儿网狐Cocos经典棋牌开发教程

由知名Cocos技术专家红孩儿讲解的基于网狐源码进行棋牌开发的系列教程。
  • 2017年09月15日 11:03

Cocos2d-x 手游聊天系统需求分析

手游聊天系统需求分析https://blog.csdn.net/wwj_748/article/details/38387471转载请注明:IT_xiao小巫移动开发狂热者群:299402133策划需...
  • tropicofcancer9
  • tropicofcancer9
  • 2018-04-21 10:01:30
  • 10

Luogu P1351 联合权值___领接表+思维

题目大意: 无向连通图G有n个点,n-1条边,点从1到n依次编号,编号为i的点的权值为Wi每条边的长度均为1图上两点(u,v)的距离定义为u点到v点的最短距离。对于图G上的点对(u,v),若它们的距...
  • Gx_Man_VIP
  • Gx_Man_VIP
  • 2018-04-21 15:30:51
  • 12

麻将的胡牌算法

转自:http://blog.csdn.net/shinefire/article/details/59118146正常的麻将胡牌方式为满足N * ABC + M *DDD +EE 的形式,及存在一个...
  • gf771115
  • gf771115
  • 2018-01-18 17:22:29
  • 184

c++实现洗牌算法源代码

  • 2009年04月18日 09:58
  • 4KB
  • 下载

关于洗牌算法的一点总结

之前写斗地主的时候简单写了一个洗牌函数,基本思路是先产生一个顺序数组,遍历数组,每次产生一个(1~n)随机数,把这个随机数作为下标取出数组里的数与当前位置的数交换。 当时也没多想,反正能打乱数组顺序...
  • huang1433
  • huang1433
  • 2015-11-08 10:31:15
  • 2029

一个高效的洗牌算法分析

0   public static void randomDeliverCard(int length) {1         int[] card1 = new int[length];      ...
  • del_del
  • del_del
  • 2006-08-23 10:04:00
  • 837

【每日算法】洗牌算法

洗牌算法 给定一个n个数的序列,设计一个算法将其随机打乱,保证每个数出现在任意一个位置的概率相同(也就是说在n!个的排列中,每一个排列出现的概率相同)。...
  • jiange_zh
  • jiange_zh
  • 2016-02-18 10:27:19
  • 1533

【算法详解】洗牌算法

1. 问题描述
  • robinjwong
  • robinjwong
  • 2014-01-14 13:44:01
  • 5447

[经典面试题]完美洗牌算法

题目有个长度为2n的数组{a1,a2,a3,…,an,b1,b2,b3,…,bn},希望排序后{a1,b1,a2,b2,….,an,bn},请考虑有无时间复杂度o(n),空间复杂度0(1)的解法。来源...
  • SunnyYoona
  • SunnyYoona
  • 2015-02-13 16:08:08
  • 7916
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 8603
    积分: 615
    排名: 8万+
    博客专栏