我有一个加权图表(实际上)最多50,000个顶点。给定一个顶点,我想根据所有相邻边的相对权重随机选择一个相邻的顶点。
如何将此图存储在内存中以便进行选择?什么是最好的算法?它可以像每个顶点的键值存储一样简单,但这可能不适合最有效的算法。我还需要能够更新网络。
请注意,我一次只想采取一个“步骤”。
更正式:给定加权,定向和可能完整的图表,让 W(a,b)为边a-> b的权重并让 W a 是来自 a 的所有边的总和。给定一个输入顶点 v ,我想随机选择一个顶点,其中选择顶点 x 的可能性是 W(v,x) / < EM> w ^ <子> v 子> 的
示例:
说 W(v,a) = 2, W(v,b) = 1, W(v,c) = 1。
给定输入 v ,该函数应返回 a ,概率为0.5, b 或 c 概率为0.25
答案 0 :(得分:7)
如果您担心生成随机游走的性能,您可以使用alias method构建一个数据结构,该数据结构非常符合您选择随机传出边缘的要求。开销只是你必须为每个有向边分配一个概率权重和一个所谓的别名边缘。
因此,对于每个音符,您都有一个传出边的向量以及权重和别名边。然后,您可以在恒定时间内选择随机边(只有edata结构的生成是相对于总边数或节点边数的线性时间)。在示例中,边缘由->[NODE]
表示,节点v
对应于上面给出的示例:
Node v
->a (p=1, alias= ...)
->b (p=3/4, alias= ->a)
->c (p=3/4, alias= ->a)
Node a
->c (p=1/2, alias= ->b)
->b (p=1, alias= ...)
...
如果要选择输出边缘(即下一个节点),则只需从间隔[0,1)生成一个随机数r
均匀。
然后,您获得no=floor(N[v] * r)
和pv=frac(N[v] * r)
,其中N[v]
是传出边的数量。即你以完全相同的概率选择每条边(即节点v
的例子中的1/3)。
然后,您将此边缘的已分配概率p
与生成的值pv
进行比较。如果pv
较小,则保持之前选择的边缘,否则您选择其别名边缘。
例如,如果我们的随机数生成器中有r=0.6
,我们就有
no = floor(0.6*3) = 1
pv = frac(0.6*3) = 0.8
因此我们选择第二个输出边(注意索引从零开始),即
->b (p=3/4, alias= ->a)
并切换到->a
后的别名边p=3/4 < pv
。
对于节点v
的示例,我们因此
b
的边1/3*3/4
(即每当no=1
和pv<3/4
时)c
的边1/3*3/4
(即每当no=2
和pv<3/4
时)a
的边1/3 + 1/3*1/4 + 1/3*1/4
(即每当no=0
或pv>=3/4
时)答案 1 :(得分:1)
理论上,绝对最有效的方法是为每个节点存储连接节点及其权重的平衡二叉树(红黑,BTree或跳过列表)的道德等价物,以及每一方的总重量。然后你可以从0到1中选择一个随机数,乘以连接节点的总权重,然后进行二分查找以找到它。
然而,遍历这样的二叉树涉及很多选择,这些选择倾向于创建管道停顿。这是非常昂贵的。所以在实践中,如果你使用有效的语言(例如C ++)进行编程,如果每个节点的连接边数少于几百个,那么你走进的线性边缘列表(带有预先计算的总和)循环可能会更快。