关于C#:有向图/网络中的随机游走

Random walks in directed graphs/networks

我有一个(实际上)多达50000个顶点的加权图。给定一个顶点,我想根据所有相邻边的相对权重随机选择一个相邻顶点。

我应该如何将此图存储在内存中,以便进行有效的选择?最好的算法是什么?它可以像每个顶点的键值存储一样简单,但这可能不适合最有效的算法。我还需要更新网络。

请注意,我一次只想迈出一步。

更正式地说:给定一个加权、有向和可能完整的图,让w(a,b)是边a->b的权重,让wa->sub>是a的所有边的总和。给定一个输入顶点v,我想随机选择一个顶点,其中选择顶点x的可能性是w(v,x)/wv->sub>

例子:

假设w(v,a)=2,w(v,b)=1,w(v,c)=1。

给定输入v,函数应返回概率为0.5的a和概率为0.25的b或c。


如果您关心生成随机漫游的性能,那么可以使用Alias方法构建一个数据结构,它非常适合您选择随机传出边缘的要求。开销只是您必须为每个定向边分配一个概率权重和一个所谓的别名边。

所以对于每个音符,都有一个输出边的向量,以及权重和别名边。然后您可以在恒定时间内选择随机边(相对于总边数或节点边数,只有生成th edata结构的时间是线性时间)。在示例中,边缘用->[NODE]表示,节点v对应于上面给出的示例:

1
2
3
4
5
6
7
8
9
10
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]生成单个随机数runiform。

然后得到no=floor(N[v] * r)pv=frac(N[v] * r),其中N[v]是出边的数量。即选取概率完全相同的每个边(即节点v中的1/3)。

然后将该边的指定概率p与生成值pv进行比较。如果pv较小,则保留之前选定的边,否则选择其别名边。

例如,如果我们有来自随机数发生器的r=0.6,我们有

1
2
no = floor(0.6*3) = 1
pv = frac(0.6*3) = 0.8

因此,我们选择第二个传出边缘(注意索引以零开头),即

1
->b (p=3/4, alias= ->a)

并切换到别名边缘->a,因为p=3/4 < pv

因此,对于节点v的示例,我们

  • 用概率1/3*3/4选择边b(即每当no=1pv<3/4时)
  • 用概率1/3*3/4选择边c(即每当no=2pv<3/4时)
  • 用概率1/3 + 1/3*1/4 + 1/3*1/4选择边a(即每当no=0pv>=3/4时)


理论上,最有效的方法是为每个节点存储平衡二叉树(红-黑,或btree,或skip-list-all-fit)的道德等价物及其权重,以及每侧的总权重。然后你可以选择一个从0到1的随机数,乘以连接节点的总权重,然后做一个二进制搜索来找到它。

然而,像这样遍历二叉树需要很多选择,这些选择往往会造成管道阻塞。很贵的。所以在实践中,如果你用高效的语言编程(如C++),如果每个节点的连接边少于几百个,那么你在一个循环中的边(具有预先计算的总和)的线性列表可能被证明是更快的。