单次遍历,带权随机选取问题
2013-10-05 22:49 youxin 阅读(1311) 评论(0) 编辑 收藏 举报在以前的链表单次遍历,随机选取问题中,我们采用水塘抽象方法解决了问题。问题结点带权呢?
问题描述:有一组数量未知的数据,每个元素有非负权重。要求只遍历一次,随机选取其中的一个元素,任何一个元素被选到的概率与其权重成正比。
设元素总数为n,当然在遍历结束前n是未知的。设第i(1 <= i <= n
)个元素的权重为wi(> 0),则权重总和为,也是在遍历结束时才知道的。根据题目要求,第i个元素被选取的概率应该等于
虽然加了个权重,但解法依旧非常简单,在单次遍历,等概率随机选取问题中的RandomSelect函数上稍作修改就得到本问题的解法,依旧是O(n)时间,O(1)辅助空间:
from random import Random def WeightedRandomSelect(rand=None): selection = None totalweight = 0.0 if rand is None: rand = Random() while True: # Outputs the current selection and gets next item (item, weight) = yield selection totalweight += weight if rand.random() * totalweight < weight: selection = item
其中Python的random.random()返回[0, 1)之间的随机小数。
把rand.random()<weight/totalWeigth,则会有好理解一点。(同等概率选取类似,random(1,i)等于1就替换.i分之一,只不过不同概率用权重占比来表示了。)
算法很简单:对于任意的i(1 <= i <= n),按照如下方法给第i个元素分配一个键值key(其中ri是一个0到1之间等概率分布的随机数):
之后,如果要随机选取一个元素,就去key最大的那个;如果要选取m个元素,就取key最大的m个。
真不知道是怎么想出来的这样的方法,不过还是先来关注一下证明的过程。
算法的核心,计算每个元素的随机权重,python版:
更多:
http://www.gocalf.com/blog/weighted-random-selection.html
http://www.gocalf.com/blog/weighted-random-selection-2.html
http://www.cnblogs.com/SuperBrothers/archive/2012/11/13/2768788.html