单次遍历,等概率随机选取问题

问题描述:假设我们有一堆数据(可能在一个链表里,也可能在文件里),数量未知。要求只遍历一次这些数据,随机选取其中的一个元素,任何一个元素被选到的概率相等。O(n)时间,O(1)辅助空间(n是数据总数,但事先不知道)。

引例:
5个人抽5个签,只有一个签意味着“中签”,轮流抽签,从很久很久以前我们就认为这个是非常公平的例子,这个应该不用去怀疑吧。如果怀疑了,好吧,看下面的分析:

分析:
设Ai为第i个人抽签抽中事件,P(Ai)表示第i个人中签的概念,依题意得:
第一个人中签概率:P(A1)=1/5;
第二个人中签概率:P(A2)=4/51/4=1/5;(因为第二个人是在第一个人选了之后才去抽的,所以,还有4/5是第一个没有选中的,剩下的四个再去抽一个所以是1/4)
同理, P(A3)=4/5
3/41/3=1/5;
P(A4)=4/5
3/42/31/2=1/5;
P(A3)=4/53/42/31/21=1/5;
就样,五个人抽到的是等概率的,相信了吧
推导
先假设链表长度为n;
我们这样做,每次取一个随机值,这个随机值是这样规定的 n=randint(0,第i个元素);
例如下面这样:n的值可能是如下结果
第一个元素时:
randint(0,1)={0};n=0;
第二个:
randint(0,2)={0,1};n=0或1
第三个:
randint(0,3)={0,1,2};n=0,或者1或者2
第四个:
randint(0,4)={0,1,2,3};
第五个:
randint(0,5)={0,1,2,3,4};
第n个:
randint(0,n)={0,1,2,3,4…,n-1,n};

假设数字0就是中签,这样一遍计算来说的话每个人取到0的概率是多少呢?没错,根据引例,概率是1/n;
也就是我们可以定义一个方法,设置一个计数器,从头到尾遍历链表。每到一个元素时,就取一下n=randint(0,count),
如果n0,则selectItem=item; selectItem这个值不一定是不变的,只要随机出的值n0,这个selectItem就会被替换。所以说必须将链表完整的遍历一遍,概率才会是1/n最后的selectItem就是等概率取出的值。
测试结果:
测试1
测试2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值