博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洗牌算法
阅读量:4969 次
发布时间:2019-06-12

本文共 1443 字,大约阅读时间需要 4 分钟。

1. 问题描述

洗牌算法是常见的随机问题;它可以抽象成:得到一个M以内的所有自然数的随机顺序数组

常见问题描述:

1.将自然数1 ~ 100随机插入到一个大小为100的数组,无重复元素

2. 1 ~ 52张扑克牌重新洗牌

 

什么是好的洗牌算法:

洗牌之后,如果能够保证每一个数出现在所有位置上的概率是相等的,那么这种算法是符合要求的;这在个前提下,尽量降低时间和空间复杂度。

 

2. 算法实现

第一个算法:

随机抽出一张牌,检查这种牌是否被抽取过,如果已经被抽取过,则重新抽取,知道找到没有被抽取的牌;重复该过程,知道所有的牌都被抽取到。

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

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

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

这种方法的时间/空间复杂度都不好。

 

第二个算法:

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

 

[cpp] view plain copy

 

 

  1. <span style="color:#999999;">void shuffle(int* array, int len)  
  2. {  
  3.     const int suff_time = len;  
  4.       
  5.     for (int idx = 0; i < suff_time; i++)  
  6.     {  
  7.         int i = rand() % len;  
  8.         int j = rand() % len;  
  9.           
  10.         int temp = array[i];  
  11.         array[i] = array[j];  
  12.         array[j] = temp;  
  13.     }  
  14. }</span>  

 

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

 

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

 

第三个算法:

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

 

[cpp] view plain copy

 

 

  1. void shuffle(int* array, int len)  
  2. {  
  3.     int i = len;  
  4.     int j = 0;  
  5.     int temp= = 0;  
  6.       
  7.     if (i == 0)  
  8.     {  
  9.         return;  
  10.     }  
  11.       
  12.     while (--i)  
  13.     {  
  14.         j = rand() % (i+1);  
  15.         temp = array[i];  
  16.         array[i] = array[j];  
  17.         array[j] = temp;  
  18.     }  
  19. }  

 

该算法的数学证明请参照具体的论文或者;

 

该算法复杂度为O(n),且各元素随机概率相等。

posted on
2017-04-30 11:09 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/jymz/p/6789058.html

你可能感兴趣的文章
【7-9 有重复的数据I (20 分)】【此题卡输入,需要自己写个输入挂】
查看>>
JRebel安装部署,激活
查看>>
OPENSSL使用方法
查看>>
下载GO的开源开发工具LITEIDE
查看>>
接口操作XML
查看>>
idhttp访问DATASNAP有密码验证的中间件
查看>>
libmidas.so.2
查看>>
开发WINDOWS服务程序
查看>>
httpencode编码
查看>>
cross socket和msgpack的数据序列和还原
查看>>
解决跨操作系统平台JSON中文乱码问题
查看>>
DELPHI搭建centos开发环境
查看>>
IdHTTPServer允许跨域访问
查看>>
更新.net core 3.0,dotnet ef命令无法使用的解决办法
查看>>
React躬行记(13)——React Router
查看>>
前端利器躬行记(1)——npm
查看>>
前端利器躬行记(2)——Babel
查看>>
前端利器躬行记(3)——webpack基础
查看>>
前端利器躬行记(4)——webpack进阶
查看>>
前端利器躬行记(5)——Git
查看>>