Algorithm 对象图表示与邻接列表和矩阵表示的比较

Algorithm 对象图表示与邻接列表和矩阵表示的比较,algorithm,graph,graph-algorithm,Algorithm,Graph,Graph Algorithm,我目前正在遵循Steve Yegge关于准备技术编程面试的建议: 在关于图表的章节中,他指出: 有三种基本的方法 表示内存中的图形(对象) 和指针、矩阵和邻接 列表),您应该熟悉 你自己与每一个代表和 它的优点和缺点 在CLR中描述了矩阵和邻接列表表示法的优缺点,但我还没有找到一个资源将它们与对象表示法进行比较 只要想一想,我自己就可以推断出其中的一些,但我想确保我没有错过一些重要的东西。如果有人能全面地描述这一点,或者给我指一个这样做的资源,我将不胜感激。对象和指针与邻接列表基本相同,至少是为

我目前正在遵循Steve Yegge关于准备技术编程面试的建议:

在关于图表的章节中,他指出:

有三种基本的方法 表示内存中的图形(对象) 和指针、矩阵和邻接 列表),您应该熟悉 你自己与每一个代表和 它的优点和缺点

在CLR中描述了矩阵和邻接列表表示法的优缺点,但我还没有找到一个资源将它们与对象表示法进行比较


只要想一想,我自己就可以推断出其中的一些,但我想确保我没有错过一些重要的东西。如果有人能全面地描述这一点,或者给我指一个这样做的资源,我将不胜感激。

对象和指针与邻接列表基本相同,至少是为了比较使用这些表示的算法

比较

struct Node {
    Node *neighbours[];
};


在后一种情况下,如果使用命名指针比使用命名指针更容易,则可以轻松地动态构建邻居列表。

对象和指针

这些只是基本的数据结构,就像哈马尔在另一个答案中所说的,在
Java
中,你可以用像边和顶点这样的类来表示。例如,边连接两个顶点,可以是有向的,也可以是无向的,并且可以包含权重。顶点可以有ID、名称等。它们大多都有附加属性。所以你可以用它们来构造你的图,就像

Vertex a = new Vertex(1);
Vertex b = new Vertex(2);
Edge edge = new Edge(a,b, 30); // init an edge between ab and be with weight 30  
这种方法通常用于面向对象的实现,因为它对于面向对象的用户来说可读性更高,也更方便;)

矩阵

矩阵只是一个简单的二维数组。假设您有可以表示为int数组的顶点ID,如下所示:

int[][] adjacencyMatrix = new int[SIZE][SIZE]; // SIZE is the number of vertices in our graph
adjacencyMatrix[0][1] = 30; // sets the weight of a vertex 0 that is adjacent to vertex 1
这通常用于需要索引访问的密集图。你可以用这个来表示一个非定向和加权的结构

邻接列表

这只是一个简单的数据结构组合,我通常使用
HashMap
实现它。在番石榴中可以使用类似的
HashMultimap

这种方法很酷,因为有O(1)(摊销)顶点查找,它会返回我所需的这个特定顶点的所有相邻顶点的列表

ArrayList<Vertex> list = new ArrayList<>();
list.add(new Vertex(2));
list.add(new Vertex(3));
map.put(new Vertex(1), list); // vertex 1 is adjacent to 2 and 3
ArrayList list=new ArrayList();
添加(新顶点(2));
添加(新顶点(3));
map.put(新顶点(1),列表);//顶点1与2和3相邻
这是用来表示稀疏图的,如果你在谷歌申请,你应该知道webgraph是稀疏的。您可以使用一种更具伸缩性的方法来处理它们


哦,顺便说一句,这篇文章有很多精彩的图片,是一个很好的总结;)

对象表示()的优点是两个相邻顶点共享相同的边实例。这使得使用无向边数据(长度、成本、流量甚至方向)进行操作变得容易。但是,它会为指针使用额外的内存。

另一个好资源:

除了邻接列表和邻接矩阵外,它们还将“边列表”列为第三种图形表示形式。边缘列表可以解释为“边缘对象”列表,就像托马斯的“对象和指针”回答中的那些

优点:我们可以存储更多关于边缘的信息(Michal提到)

缺点:它的数据结构非常慢:

  • 查找边:O(日志e)
  • 移除边缘:O(e)
  • 查找与给定节点相邻的所有节点:O(e)
  • 确定两个节点之间是否存在路径:O(e^2)

e=边数

这种方法很酷,因为有O(1)个顶点查找,这种复杂性稍有错误,尤其是O(1+alpha),其中alpha=哈希映射中的槽数/顶点数。因此,我建议使用数组而不是散列map@Tim按O(1)摊销。您的复杂性计算强烈依赖于实现。请参阅
HashMap
()的javadoc,它说:
此实现为摊销的基本操作
=O(1)提供了恒定的时间性能。@Tim我想这里的每个人都知道数组访问比任何
哈希表
使用都要快。因此,没有必要在一个可以忽略的小的恒定阿尔法开销上吹毛求疵。请不要误会我,我不会冒犯你的回答很好,但我感觉你的答案可能会有所改进,所以为什么不在这里提及:)@Tim我在答案中添加了摊销注释。谢谢。为什么有一个名为“关联列表”的邻接列表表示的链接?也许用这个比较好,那么-这三个类别属于哪一个呢?
ArrayList<Vertex> list = new ArrayList<>();
list.add(new Vertex(2));
list.add(new Vertex(3));
map.put(new Vertex(1), list); // vertex 1 is adjacent to 2 and 3