这里想记录一个之前遇到的一个很有意思的与大随机数相关的问题,也是自己长时间琢磨出来的结果,这里想分享一下;
先在这里列出结果方便读者看是否相关,以免浪费你的时间,这里想通过一个小例子得出如下的结果:
1) 通常的离散型均匀分布的产生;
2) 大随机数的离散型均匀分布的产生;
3) 大量数据,在范围已知或可估计的条件下的,简单快速排序算法:O(range)的空间O(n)的时间
4) 数据分布可估计时的基于统计的高成功率的快速查找,进一步的节省空间和时间,且错误概率可控,直至为零
如果想来看看,你爱我们就开始了:
首先给出问题(很短,其实就一句话):
生成N=10^12个范围在0~(10^8)-1之间的整数,并找出其中第N/2大和第N/4大的数。
咋看之下这个问题似乎很简单,只是数据量很大而已。可是仔细一想似乎数据大的有点多了,因此其存储倒是问题(因为我们后面还需要寻找N/2大和第N/4大的数),还有一个问题就是,C++中的rand()生成的随机数是不会超过RAND_MAX(0x7fff)的,而RAND_MAX是小于(10^8)的,所以随机数的生成也是一个问题,还有就是,即便我们可以生成10^8的随机数,但是如果10^8进一步变大的话(如:变为10^9)还是会面临随机数生成的问题,所以有必要找到一种利用已有随机数生成函数生成大随机数的方法。
首先这里先来解决第一个问题,大随机数生成:
其实,看到这个问题可能很多人已经想到解决方案了,或者是google之,或者是baidu之,都可以得到几种解决方案,
例如:
示例1(注意这样是有问题,下面会分析):
srand(time(NULL));
int r1=rand()%10000;
int r2=rand()%10000;
int re=r1*r2;
示例2(这里也有点问题,下面会解决):
srand(time(NULL));
int r1=rand()%10000;
int r2=rand()%10000;
int re=r1*10000+r2;
如果你对为随机数的生成方法比较熟悉的话那么你也可以自己写一个随机数生产函数,如 http://blog.youkuaiyun.com/suiyunonghen/article/details/3863260 所做的那样,但是我们可能更愿意使用C++标准提供的随机数生产函数,而且博文中关于随机数种子的部分处理得并不理想,因而这种方法存在一些问题,文中自己也有提到。
而对于第一种方法,他是最不推荐使用的方法,理由如下:
首先,我们需啊明白的的是,这里所说的随机数是指均匀分布,也就是:P(re=n)=1/N这里N=10^8,re就是产生的随机数,而示例1产生的随机数根本就不是均匀分布(这里我们假设rand()%10000是服从均匀分布的,(其实这会有一点问题,但是后面会细说并改正它,这里先使用后面的结果):
证明:
其实要证明他不是均匀分布只需要举出一个反例就好了,以上面的情况为例:示例1中的算法产生数字6的情况为:(r1, r2)=(1,6)或(2,3)或(3,2)或(6,1),每一个的概率为1/N*1/N*6=1/10000*1/0000*6=6/(10^8)但是对于数字10001,示例1中的代码是根本不可能产生的,而其进一步的我们可以看到的是这种现象是普遍存在的,而并是特例,这是上面的代码的固有问题。
对于示例2,类似于前面的步骤,这里先计算取到0~(10^8)-1之间任意一个数的概率,根据示例2中的代码这里利用如下的步