简单的问题,还没有找到一个简单的答案。我想要一个具有N个顶点,M个边缘,均匀随机的图形。在合理的时间复杂性(我说最差的是拟线性)。这样的算法是否存在,如果是,它是什么?
编辑: 澄清:图表是无向的,没有多边或环边。
答案 0 :(得分:3)
应该是直截了当的。只需生成N
个顶点。然后M
边缘。选择随机顶点作为源和目标。由于您没有其他要求(如自动机语言),因此均匀分布。
V <- {1, ..., N}
E <- {}
for 1 to M do
edge <- (random(V), random(V))
E.push(edge)
return (V, E)
编辑:澄清:图表是无向的,没有多边或循环。
继续生成随机边,直到有一个有效边:
V <- {1, ..., N}
E <- {}
for 1 to M do
repeat
source <- random(V)
edge <- (source, random(V \ {source}))
until E does not contain edge
E.push(edge)
return (V, E)
目的地使用random(V \ source)
排除循环。 E does not contain edge
不应该关心方向。即应该考虑
(a, b) = (b, a)
为了contains
的效率,你应该在实现时使用一些散列结构。
问题是repeat
循环。取决于random
的工作速度以及M
与可能边缘的距离有多近,可能需要一段时间。您可以使用Floyd-Rivest algorithm等技术加快速度(另请参阅Algorithm to select a single, random combination of values?)。
如果M
相当小,则与最大数量相比,它应该快速运行(N
和M
中的线性),因为您没有遇到大量边缘碰撞。
答案 1 :(得分:1)
要有效生成随机图,您可以使用Erdős–Rényi model。 它是图论中的经典方法。 Java代码(使用graphstream库)生成随机图类似于:
Graph g = new SingleGraph("Erdos-Renyi model");
// adding the first nodes
g.addNode("0");
g.addNode("1");
// creates the first edge
g.addEdge("0_1", "0", "1");
Integer i = 2;
while(i < numNodes) {
Node source = g.addNode(i.toString());
Node dest = g.getNode(random.nextInt(i)+"");
g.addEdge(source.getId() + "_" + dest.getId(), source.getId(), dest.getId());
i++;
}
还有其他模型可以生成Barabási–Albert model等图表。该模型生成一个图表,其中节点连接越多,接收新链接的可能性就越大(描述富有的富裕现象)。使用Barabási-Albert模型生成随机图的Java代码是:
Graph g = new SingleGraph("Barabasi–Albert model");
g.addNode("0");
g.addNode("1");
g.addEdge("0_1", "0", "1");
int sumDegree = 2;
Integer i = 2;
while(i < numNodes) {
Node source = g.getNode(i.toString());
if(source == null) {
source = g.addNode(i.toString());
}
Node dest = g.getNode(random.nextInt(i)+"");
double probability = dest.getDegree() * 1.0/sumDegree;
double r = nextDouble();
if(probability > r) {
g.addEdge(source.getId() + "_" + dest.getId(), source.getId(), dest.getId());
sumDegree = sumDegree + 2;
i++;
}
}
另一种着名的方法是使用Watts–Strogatz model生成具有小世界属性的随机图。在这种情况下,大多数节点不是彼此的邻居。但是,任何给定节点的邻居很可能是彼此的邻居,并且可以通过少量跳跃从每个其他节点到达大多数节点。
如您所见,生成随机图有几种可能性。根据所需的网络特性,应使用特定的模型。