如何生成随机图形?

11
我希望能够在Java中生成随机的、无向的、连通的图,同时也希望能够控制图中顶点的最大数量。我不确定如何最好地解决这个问题,但以下是我能想到的几种方法:
(1) 生成一个介于0和n之间的数字,并将其作为顶点数。然后,以某种方式随机连接顶点(也许为每个顶点生成一个随机数,然后将其作为从该顶点出发的边的数量)。从任意顶点开始遍历图(例如使用广度优先搜索),并让我们的随机图G为所有访问过的节点(这样,我们可以确保G是连通的)。
(2) 生成一个随机的方阵(由0和1组成),其边长介于0和n之间(以某种方式)。这将是我们的图的邻接矩阵(然后对角线上的元素应全部为1或全部为0)。从任何节点遍历图,以获取一组连接的节点,并将其称为图G。
欢迎采用其他任何方法来生成足够随机的图。注意:我不需要完全随机的图,即您生成的图不必具有任何特殊的数学属性(如某种均匀性)。我只需要大量的图来测试其他东西。
这是我使用的Java Node类:
public class Node<T> {
    T data;
    ArrayList<Node> children= new ArrayList<Node>();
    ...}

这是我正在使用的Graph类(你可以看出为什么我目前只对连通图感兴趣):

public class Graph {
    Node mainNode;
    ArrayList<Node> V= new ArrayList<Node>();

    public Graph(Node node){
        mainNode= node;
    }
    ...}

作为一个例子,这是我目前用于测试的制作图表的方法:
//The following makes a "kite" graph G (with "a" as the main node).

/*     a-b
        |/|
        c-d
*/
Node<String> a= new Node("a");
Node<String> b= new Node("b");
Node<String> c= new Node("c");
Node<String> d= new Node("d");
a.addChild(b);
a.addChild(c);
b.addChild(a);
b.addChild(c);
b.addChild(d);
c.addChild(a);
c.addChild(b);
c.addChild(d);
d.addChild(c);
d.addChild(b);
Graph G1= new Graph(a);

你可以使用像Java的Quickcheck这样的随机数据生成库。然而,这样的库通常没有内置方法来生成图形,所以这可能有点棘手。试一试,如果遇到问题,请回复。 - Robin Green
我会将这两种方法结合起来。首先,通过将一个不在图中的随机节点连接到其中一个随机节点,创建一个简单的连通图。然后从未选择的可能顶点(矩阵中的0)中选择一个数字添加到图中,使其更加密集。 - millimoose
@RobinGreen,尽管 Quickcheck 看起来可以帮助生成原语,但我仍然需要生成包含这些原语的“节点”(这是更困难的部分)。我也在寻找更明确的构造方式,而不使用库。 - under_the_sea_salad
1
@bourbaki4481472 [与此问题无关] 我看到您已删除了您的最近的问题。只是想让您知道,这里有一个解决方案,您可能会感兴趣 https://jsfiddle.net/DerekL/Lh3fy5dr/ - Derek 朕會功夫
@Derek朕會功夫,我刪除了我的問題,因為我認為我沒有解釋清楚(而且我碰巧已經找到了如何做到這一點)。我現在正在查看您的解決方案,謝謝! - under_the_sea_salad
1
@bourbaki4481472 我刚刚更新了代码(https://jsfiddle.net/DerekL/Lh3fy5dr/1/),现在更加简洁...希望能有所帮助。 - Derek 朕會功夫
3个回答

18

无论你想用图表做什么,我猜测它的密度也是一个重要的参数。否则,你只会使用随机大小生成一组小团(完全图),然后将它们随机连接起来。

如果我正确的话,我建议你使用Erdős-Rényi模型:它简单易懂,与你最初提出的不远,而且允许你控制图的密度(基本上就是链接数)。

以下是该模型的简短描述:

  1. 定义一个概率值p(p越高,图越密集:0=没有链接,1=完全连接的图);
  2. 创建你的n个节点(作为对象、邻接矩阵或任何适合你的东西);
  3. 每对节点都有一个(独立的)概率p相连。因此,你必须使用这个概率p决定它们之间是否存在链接。例如,我猜你可以在0到1之间随机抽取一个值q,当且仅当q < p时创建链接。然后对图中每个可能的节点对执行相同的操作。
使用这个模型,如果你的p足够大,那么你的图形高度可能是连通的(详见维基百科参考资料)。无论如何,如果你有几个组件,你也可以通过在不同组件的节点之间创建链接来强制它的连通性。首先,你需要通过执行广度优先搜索(每个组件一个)来识别每个组件。然后,选择两个不同组件中的节点对,创建它们之间的链接,并将两个组件视为合并。重复此过程,直到只剩下一个组件。

感谢您的解释和链接。这个模型可能适合我。 - under_the_sea_salad
虽然我必须说,我有点困惑于维基百科文章所讨论的这两个模型之间的区别。 - under_the_sea_salad
2
在第一个模型中,考虑所有符合一些参数(节点数和链接数)的可能图形,并随机选择一个。在第二个模型中,通过向最初为空的图形随机添加链接来构建图形。我发现第二个模型更适合实现,因此这是我在帖子中呈现的一个。 - Vincent Labatut

3
唯一棘手的部分是确保最终的图是连通的。为此,您可以使用不相交集数据结构。跟踪组件数,最初为n。重复选择随机顶点对u和v,将边(u,v)添加到图形和不相交集结构中,并在该结构告诉您u和v属于不同组件时将组件计数减少。当组件计数达到1时停止。(请注意,使用邻接矩阵简化了管理边(u,v)已经存在于图形中的情况:在这种情况下,adj [u] [v]将第二次设置为1,这样就没有效果了。)
如果您发现这会创建过于密集(或过于稀疏)的图形,则可以使用另一个随机数仅在端点已经属于同一组件(或属于不同组件)的情况下k%的时间添加边缘,其中k是某个值。

谢谢。关于在邻接矩阵中将 adj[u][v] 设置为1(一旦确定了两个不相交的集合),这是一个很好的观点,因为这有助于解决这个问题。 - under_the_sea_salad

1
下面的论文提出了一种算法,可以均匀地采样具有预定度数序列的连通随机图,并带有高效实现。它可在多个库中使用,例如Networkit或igraph。 使用预定度数快速生成随机连接图。 Fabien Viger,Matthieu Latapy
在对随机图进行模拟时要小心:如果它们不是均匀采样的,则可能具有影响模拟的隐藏属性;或者,均匀采样的图可能与您的代码在实践中遇到的图非常不同...

你好,欢迎来到SO!请阅读tour如何撰写优质答案?。添加链接是很好的,但解释它们如何解决问题会更好。 - Tomer Shetah
感谢@TomerShetah的评论。我的链接是解决这个问题的一篇论文,它在我回答开头所解释的上下文中(均匀生成,规定度数)精确地解决了这个问题。您的意思是我应该在这里总结算法吗?这样做是否会显得冗余和过于复杂? - Matthieu Latapy
你不应该参考其他网站来获取完整的答案。可以看一下被接受的答案作为例子。 - Tomer Shetah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接