问题:
我有一些有权重的项目。权重越高,项目优先的可能性就越大。我需要一个基于核心Java的干净、简单的方法来完成这个任务(没有第三方库、jar等)。
我已经对2个项目做了这个,通过求和权重,然后在这个范围内随机选择一个数字,使用Math.random()
。非常简单。但是对于大于2的项目,我可以在相同的范围内做更多的样本,以偶然的失误,或者我可以重新计算剩余项的权重之和并再次选择(递归方法)。我认为可能有一些东西可以做得更快/更干净。这段代码将被反复使用,所以我正在寻找一个有效的解决方案。
从本质上讲,它就像随机化的权重排列。
部分示例:
A
的权重为1,B
的权重为99。如果我使用此函数运行模拟,我希望在99%的情况下得到BA
,在1%的情况下得到AB
。A
的权重为10,B
的权重为10,C
的权重为80。如果我用这个进行模拟,我会期望C
在80%的情况下是排序中的第一个项目,在这些情况下,A
和B
成为下一个字符的机会相等。
额外详细信息:
对于我的特定问题,有一小部分项目具有潜在的较大权重。比如说20到50个具有权重的项目以long的形式存储,其中最小权重至少为1000。项目的数量也可能会增加很多,所以如果我们能找到一个不要求项目较小的解决方案,那将是首选。
5条答案
按热度按时间qvtsj1bj1#
您有重量为的项目:
首先将所有重量相加:42 + 5 + 96 + 33 = 176个
现在,从0到权重之和之间选取一个随机数r:0〈= r〈176。我使用了整数,但是如果需要的话,你可以使用实数。
将r与权重定义的范围进行比较:
当你挑选完第一件物品后,对剩下的三件物品重复这个过程,并减少所有物品的重量。不断重复,直到没有更多的物品可供挑选。
sqyvllje2#
这似乎很有效:
基本上,对于每一个要排序的项目,我都会根据需要多次将其添加到一个新列表中,然后对列表进行洗牌,将最上面的项目拉出,并从剩余的项目中清除所有出现的项目。
上次测试运行生成:
这似乎是正确的。
NB -至少在以下条件下,该算法将失败:
1.原始数组中多次包含同一对象。
1.这些物品的重量大得吓人。
1.零或负权重几乎肯定会影响结果。
已添加
这实现了Rossum的想法--请务必将算法归功给予他。
4uqofj5v3#
当然,如果我们重写TreeMap,使其允许我们添加重复键,我们会有更好性能。
piztneat4#
我已经找到了另一个答案的解决方案-现在找不到,但它使用指数分布:
对于权重为
w_i
的i-th
元素,分配一个键power(random(0,1),1.0/w_i)
(伪代码),然后按键对元素进行排序,这将花费O(n*log(n))
时间,复杂度与实际权重无关。4nkexdtk5#
无论如何,对于N个项目,你将需要N-1个随机数(至少)。然后,让我们思考有效的方法来选择项目的随机数。
如果项目不是太多,我会使用迭代的方法,类似于你的递归方法。我会添加布尔标记到项目,跳过在以前的迭代中选择的项目。当我在当前迭代中选择一个项目时,我会将它的标记设置为true,下次我将从计算中跳过它。从和中减去它的权重,并进行下一次迭代。
如果项目的数量很大,同一个集合将被多次使用,那么不同的方法是更好的。使他们排序的列表,并使用这个列表的副本在您的递归方法。并在每个递归步骤-二分搜索,然后删除选择的项目。
实际上,最后一个也可以迭代完成。