我正在尝试寻找一种高效的算法来生成一个给定稀疏度的简单连通图。类似于:
Input:
N - size of generated graph
S - sparseness (numer of edges actually; from N-1 to N(N-1)/2)
Output:
simple connected graph G(v,e) with N vertices and S edges
我正在尝试寻找一种高效的算法来生成一个给定稀疏度的简单连通图。类似于:
Input:
N - size of generated graph
S - sparseness (numer of edges actually; from N-1 to N(N-1)/2)
Output:
simple connected graph G(v,e) with N vertices and S edges
ypnos在这里给出了基于分区的答案,但是在每次选择新边的一个端点时,总会选择一个已访问过的节点,从而引入偏差。通过在每次迭代中随机选择一个已访问过的节点,可以使被访问得更早的节点具有更多的迭代机会,因此,先前的节点比后面选择的节点更有可能具有高度(边数)。
例如,在一个由4个节点组成的连通图中,不要生成线性的路径图(占所有可能生成树的75%),这种偏差将导致星形图的生成概率大于它应该有的25%。
偏差并不总是一件坏事。事实证明,这种偏差对于生成类似于真实计算机网络的生成树是有好处的。但是,为了创建一个真正随机的连通图,必须从可能的生成树集中均匀选择初始生成树(请参见维基百科的均匀生成树文章)。
一种生成均匀生成树的方法是通过随机游走。以下是Wilson在论文Generating Random Spanning Trees More Quickly than the Cover Time中描述的简单随机游走算法的引用。
这对于简单的连通图很有效,但如果您需要针对有向图的算法,请进一步阅读此文,因为它描述了Wilson算法。这里还有另一个关于随机生成生成树和Wilson算法的资源。从任何一个顶点开始,在图上进行简单的随机游走。每次首次遇到一个顶点时,标记发现它的边。当所有顶点都被发现时,标记的边就形成了一棵随机生成树。此算法易于编码,运行时间常数小,并且有一个很好的证明,证明它能生成具有正确概率的树。
由于我也对这个问题感兴趣,所以编写了Python实现各种方法,包括随机漫步方法。请随意查看GitHub上代码Gist of the code。
以下是随机漫步方法代码的摘录:
# Create two partitions, S and T. Initially store all nodes in S.
S, T = set(nodes), set()
# Pick a random node, and mark it as visited and the current node.
current_node = random.sample(S, 1).pop()
S.remove(current_node)
T.add(current_node)
graph = Graph(nodes)
# Create a random connected graph.
while S:
# Randomly pick the next node from the neighbors of the current node.
# As we are generating a connected graph, we assume a complete graph.
neighbor_node = random.sample(nodes, 1).pop()
# If the new node hasn't been visited, add the edge from current to new.
if neighbor_node not in T:
edge = (current_node, neighbor_node)
graph.add_edge(edge)
S.remove(neighbor_node)
T.add(neighbor_node)
# Set the new node as the current node.
current_node = neighbor_node
# Add random edges until the number of desired edges is reached.
graph.add_random_edges(num_edges)
|E| < (|N| - 1)
,则需要添加额外的边(高级别想法的第二点)。在示例代码中,num_edges
的值本身是不明确的。这取决于 add_random_edged()
的实现方式,它是指定所请求的总边数还是应该添加的新边数。 - Wesley Baugh根据 Wesley Baugh 的回答,我使用 cytoscape.js 实现了以下javascript代码来处理图表:
function generateRandomGraph(cy, numNode, avgDegree, weightMin, weightMax) {
// create nodes
for (var i = 0; i < numNode; i++) {
cy.add({
group: "nodes",
data: {
id: "n" + i
}
});
}
// perform random walks to connect edges
var nodes = cy.nodes(),
S = nodes.toArray(),
T = []; // visited
var currNodeIdx = randomIntBetween(0, S.length);
var currNode = S[currNodeIdx];
S.splice(currNodeIdx, 1);
T.push(currNode);
while (S.length > 0) {
var neighbourNodeIdx = randomIntBetween(0, S.length);
var neighbourNode = S[neighbourNodeIdx];
cy.add({
group: "edges",
data: {
weight: randomIntBetweenInclusive(weightMin, weightMax),
source: currNode.id(),
target: neighbourNode.id()
}
});
S.splice(neighbourNodeIdx, 1);
T.push(neighbourNode);
currNode = neighbourNode;
}
// add random edges until avgDegree is satisfied
while (nodes.totalDegree() / nodes.length < avgDegree) {
var temp = sampleInPlace(nodes, 2);
if (temp[0].edgesWith(temp[1]).length === 0) {
cy.add({
group: "edges",
data: {
weight: randomIntBetweenInclusive(weightMin, weightMax),
source: temp[0].id(),
target: temp[1].id()
}
})
}
}
}
generateRandomGraph(cy, 20, 2.8, 1, 20);
如果需要完整的示例源代码,请访问我的GitHub资料库 :)