设计一个快速算法,重复生成数字 离散分布:给定一个非负实数的数组a [] 总和为1,目标是以概率a [i]
返回索引i
我在一本在线算法手册“Java编程入门”,第4.2章:排序和搜索(http://introcs.cs.princeton.edu/java/42sort/)中找到了这个问题。
提示说:
形成累积和的数组s [],使得s [i]是[]的前i个元素的总和。现在,生成0到1之间的随机实数r,并使用二进制搜索返回索引i,其中s [i]≤s[i + 1]。
一些我怎么也无法理解提示,因此无法找到解决方案..
答案 0 :(得分:8)
有很多方法可以解决这个问题。 This article 描述了众多方法,优势,弱点和运行时。最后得出一个算法,该算法需要O(n)预处理时间,然后在每个时间O(1)生成数字。
您正在寻找的特定方法在“轮盘赌选择”下进行了描述。
希望这有帮助!
答案 1 :(得分:2)
这是一个实现'轮盘赌'技术的Python算法。如果没有图形,很难解释。通过templatetypedef链接的文章应该做得很好。另外,请注意,此算法实际上并不需要对权重进行规范化(它们不需要总和为1),但这仍然有效。
import random
trials = 50
selected_indices = []
# weights on each index
distrib = [0.1, 0.4, 0.2, 0.3]
index = random.randrange(0, len(distrib) - 1)
max_weight = max(distrib)
B = 0
# generate 'trials' random indices
for i in range (trials):
# increase B by a factor which is
# guaranteed to be much larger than our largest weight
B = B + random.uniform(0, 2 * max_weight)
# continue stepping through wheel until B lands 'within' a weight
while(B > distrib[index]):
B = B - distrib[index]
index = (index + 1) % len(distrib)
selected_indices.append(index)
print("Randomly selected indices from {0} trials".format(trials))
print(selected_indices)
答案 2 :(得分:0)
这是来自wakkerbot / megahal的片段。这里的权重是(无符号)整数,它们的总和在node-> childsum中。为了获得最大速度,子项按降序排序(或多或少)。 (权重预计具有幂律分布,只有少数高权重和许多较小权重)
/*
* Choose a symbol at random from this context.
* weighted by ->thevalue
*/
credit = urnd( node->childsum );
for(cidx=0; 1; cidx = (cidx+1) % node->branch) {
symbol = node->children[cidx].ptr->symbol;
if (credit < node->children[cidx].ptr->thevalue) break;
/* 20120203 if (node->children[cidx].ptr->thevalue == 0) credit--; */
credit -= node->children[cidx].ptr->thevalue;
}
done:
// fprintf(stderr, "{+%u}", symbol );
return symbol;
答案 3 :(得分:0)
根据粒度,您可以使用100,1000或10000元素创建索引。假设分布(a,b,c,d)与p =(10%,20%,30%,40%),我们创建一个地图:
val prob = Map ('a' -> 10, 'b' -> 20, 'c' -> 30, 'd' -> 40)
val index = (for (e <- prob;
i <- (1 to e._2)) yield e._1 ).toList
index: List[Char] = List(a, a, a, a, a, a, a, a, a, a,
b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b,
c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c,
d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d, d)
我们现在可以非常快速地选择所需概率的元素:
val x = index (random.nextInt (100))
x现在是40%d,10%a,依此类推。设置简短,快速访问。
这些数字甚至不需要总计100,但你必须计算一次范围,然后:
val max = prob.map (_._2).sum
val x = index (random.nextInt (max))