【问题标题】:Graph Implementations: why not use hashing?图实现:为什么不使用散列?
【发布时间】:2013-08-21 22:04:02
【问题描述】:

我正在准备面试和审查图表实现。我经常看到的是邻接表和邻接矩阵。当我们考虑基本操作的运行时,为什么我从来没有看到使用散列的数据结构?

例如,在 Java 中,邻接列表通常是 ArrayList<LinkedList<Node>>,但为什么人们不使用 HashMap<Node, HashSet<Node>>

设 n = 节点数,m = 边数。

在这两种实现中,删除节点 v 涉及搜索所有集合并删除 v。在邻接列表中,这是 O(n^2),但在“邻接集”中,是 O(n)。同样,删除一条边包括从 v 的列表中删除节点 u 和从 u 的列表中删除节点 v。在邻接列表中,这是 O(n),而在邻接集中,是 O(1)。其他操作,例如查找节点后继,查找两个节点之间是否存在路径等,对于这两种实现都是相同的。空间复杂度也是 O(n + m)。

我能想到的邻接集的唯一缺点是添加节点/边的摊销是 O(1),而在邻接列表中这样做确实是 O(1)。

也许我没有看到任何东西,或者我在计算运行时间时忘记考虑一些事情,所以请告诉我。

【问题讨论】:

标签: algorithm graph runtime adjacency-list


【解决方案1】:

与 DavidEisenstat 的回答一样,图的实现差异很大。这是在讲座中不太容易理解的事情之一。有两种概念设计:

1) Adjacency list
2) Adjacency matrix

但您可以轻松地增强任一设计以获得更快的插入/删除/搜索等属性。代价往往只是存储额外的数据!考虑实现一个相对简单的图算法(如... Euler's),看看您的图实现如何对运行时复杂度产生巨大影响。

为了更清楚地说明我的观点,我是说“邻接列表”实际上并不要求您使用LinkedList。例如,wiki 在他们的page 上引用了这一点:

Guido van Rossum 建议的实现使用哈希表来关联 图中的每个顶点都带有一组相邻顶点。在这 表示,一个顶点可以由任何可散列对象表示。有 没有将边明确表示为对象。

【讨论】:

    【解决方案2】:

    我们可能通常看不到这种表示,因为很少需要检查任意边是否在图中(我想不出任何依赖于它的日常图算法),并且在需要它的地方,我们可以对整个图只使用一个哈希图,存储对 (v1, v2) 来表示边。这似乎更有效率。

    (大多数常见的图算法都说“对于顶点 v 的每个邻居,做......”,然后邻接表是完美的。)

    【讨论】:

      【解决方案3】:

      为什么人们不使用HashMap<Node, HashSet<Node>>

      除非同一组节点上有多个图,否则HashMap可以替换为Node的成员变量。

      HashSetLinkedList 的问题更有趣。我猜想,对于稀疏图,LinkedList 在时间(对于等效渐近复杂度的操作)和空间上都会更有效。我对这两种表示方式都没有太多经验,因为根据算法要求,我通常更喜欢(i)将邻接列表存储为连续的子数组,或者(ii)为每条边提供一个明确的对象或存储信息的对象对关于边(例如,权重)并参与两个循环双向链表(我自己的实现,因为Java和C++标准库不支持侵入式数据结构),使得节点删除与节点和边删除的程度成正比 O (1).

      您为哈希引用的运行时间并不是最坏的情况,只是针对不经意的对手的高概率,尽管它们可以以进一步降低常数因子为代价来摊销。

      【讨论】:

        【解决方案4】:

        许多理论问题涉及一组固定的顶点和边 - 没有删除。

        许多/大多数图形算法涉及简单地遍历邻接列表中的所有边或更复杂的东西(需要额外的数据结构)。

        鉴于上述情况,您可以获得数组的所有优点(例如 O(1) 随机访问、空间高效)来表示没有任何缺点的顶点(例如固定大小、O(n) 搜索/索引插入/删除),以及链表的所有优点(例如 O(1) 插入,对于未知数量的元素的空间效率)来表示没有任何缺点的边(O(n) 搜索/随机访问)。

        但是...散列呢?

        当然,散列对于所需操作具有相当的效率,但常数因素更差,并且存在不可预测性,因为性能取决于良好的散列函数和分布良好的数据。

        现在不是你不应该使用散列的规则,如果你的问题需要它,那就去吧。

        【讨论】:

        • Given the above, you get all of the advantages of an array ... and all the advantages of a linked-list - 你指的是什么数据结构?我不确定您是指使用HashSet 或其他东西的OP 想法。
        • @max 数组表示顶点,链表表示边(所以ArrayList<LinkedList>)。有时您不会从某些优点中获得太多好处,而缺点会极大地影响您,在这种情况下,另一种数据结构可能更可取。
        猜你喜欢
        • 2012-03-10
        • 2013-12-08
        • 2011-07-30
        • 2021-08-02
        • 2021-10-14
        • 1970-01-01
        • 2011-01-29
        • 2011-06-03
        相关资源
        最近更新 更多