将对象图表示与邻接表和矩阵表示进行比较

Posted

技术标签:

【中文标题】将对象图表示与邻接表和矩阵表示进行比较【英文标题】:Comparing object graph representation to adjacency list and matrix representations 【发布时间】:2011-08-18 16:20:05 【问题描述】:

我目前正在听从 Steve Yegge 关于准备技术编程面试的建议:http://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html

在他关于图表的部分中,他说:

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

矩阵和邻接表表示的优缺点在 CLRS 中进行了描述,但我无法找到将这些与对象表示进行比较的资源。

通过思考,我可以自己推断出一些,但我想确保我没有错过一些重要的事情。如果有人可以全面地描述这一点,或者向我指出这样做的资源,我将不胜感激。

【问题讨论】:

inductive graphs 怎么样?它们属于 3 个类别中的哪一个? 【参考方案1】:

对象和指针

这些只是 hammar 在另一个答案中所说的基本数据结构,在 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<Vertex, List<Vertex>> 来实现它。类似使用的可以是 Guava 中的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

这是用来表示稀疏图的,如果你在谷歌申请,你应该知道网络图是稀疏的。您可以使用BigTable 以更具可扩展性的方式处理它们。

哦,顺便说一句,here 用精美的图片很好地总结了这篇文章;)

【讨论】:

这种方法很酷,因为你有 O(1) 顶点查找 这种复杂性有点错误,特别是 O(1+alpha) 其中 alpha = num of哈希映射中的插槽/顶点数。因此我建议使用数组而不是哈希图 @Tim 它是 O(1) 摊销的。您的复杂性计算强烈依赖于实现。请参阅HashMap (docs.oracle.com/javase/7/docs/api/java/util/HashMap.html) 的 javadoc,它说:This implementation provides constant-time performance for the basic operations = O(1) amortized。 @Tim 我想这里的每个人都知道数组访问比任何HashTable 使用都快。因此,无需使用可以忽略的小的恒定 alpha 开销来挑剔。 请不要误会,我不会冒犯你的好答案,但我感觉你的答案可能会有所改进,所以这里为什么不提:) @Tim 我将摊销票据添加到答案中。谢谢。【参考方案2】:

对象和指针大多与邻接表相同,至少在比较使用这些表示的算法时是这样。

比较

struct Node 
    Node *neighbours[];
;

struct Node 
    Node *left;
    Node *right;
;

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

【讨论】:

【参考方案3】:

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

【讨论】:

为什么有一个指向名为“incidence list”的邻接表表示的链接?可能还是用这个比较好algorithmist.com/index.php/Graph_data_structures#Incidence_List【参考方案4】:

另一个好资源:Khan Academy - "Representing Graphs"

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

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

缺点:这是一个非常慢的数据结构:

查找一条边:O(log e) 删除一条边:O(e) 查找与给定节点相邻的所有节点:O(e) 判断两个节点之间是否存在路径:O(e^2)

e = 边数

【讨论】:

以上是关于将对象图表示与邻接表和矩阵表示进行比较的主要内容,如果未能解决你的问题,请参考以下文章

图的邻接矩阵与邻接表

用数组表示的邻接表,如何添加一个弧

邻接表的简介

第六章学习小结

(王道408考研数据结构)第六章图-第二节1:图的存储结构(邻接矩阵邻接表十字链表和邻接多重表)

图的表示及搜索算法