我正在尝试找到一种有效的算法来生成具有给定稀疏性的简单连通图。类似的东西:
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
答案 0 :(得分:32)
partition-based answer ypnos是一个良好的开端,但始终为新边缘的一端选择一个访问节点会引入偏差。通过在每次迭代中随机选择一个访问节点,开始访问的节点具有更多迭代,从中可以选择它们。因此,较早的节点更可能具有高度(边数)而不是稍后选取的节点。
例如,对于4节点连通图而不是生成线性path graph,这是75%的可能生成树,这种偏差将导致star graph成为生成的概率应该超过25%。
偏见并不总是坏事。事实证明,这种偏差有利于生成类似于现实世界计算机网络的生成树。但是,为了创建一个真正随机连接的图形,必须从可能的生成树集合中统一选取初始生成树(参见维基百科的Uniform Spanning Tree文章)。
生成统一生成树的一种方法是通过随机游走。以下是Wilson撰写的文章Generating Random Spanning Trees More Quickly than the Cover Time中引用的简单random walk算法。
从任何顶点开始,在图表上进行简单的随机游走。每次遇到顶点时,都要标记发现它的边。当发现所有顶点时,标记的边形成随机生成树。该算法易于编码,运行时间常数较小,并且可以很好地证明它可以生成具有正确概率的树。
这适用于简单的连通图,但是如果你需要一个有向图的算法,那么进一步阅读paper,因为它描述了Wilson的算法。这是random spanning trees和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)
答案 1 :(得分:19)
对于每个节点,您至少需要一条边。
从一个节点开始。 在每次迭代中,创建一个新节点和一个新边。边缘是将新节点与前一个节点集中的随机节点连接起来。
创建所有节点后,创建随机边缘,直到满足S为止。确保不要创建双边(为此你可以使用邻接矩阵)。
随机图在O(S)中完成。
答案 2 :(得分:2)
根据Wesley Baugh的答案,我想出了以下javascript实现cytoscape.js来处理图表:
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);
有关完整的示例源代码,请访问my github repo:)
答案 3 :(得分:1)
使用类似minimum spanning tree的内容生成Prim's algorithm,然后根据您想要的稀疏度随机生成其他链接。