8

我需要存储一个有向图(不一定是非循环的),以便尽可能快地删除节点。我不介意存储额外的数据,以便确切知道删除节点时必须走哪些边。

如果我存储一个边列表(作为节点索引对),那么当杀死某个节点 n 时,我必须在整个列表中搜索其源或目标为 n 的边。这对我的申请来说太昂贵了。可以通过在节点中存储一些额外的数据来避免这种搜索吗?

一种想法是让每个节点将其自己的源和目标存储为两个单独的列表。当节点 n 被杀死时,它的列表也被杀死。但是,链接到节点 n 的所有目标/源如何知道更新他们自己的列表(即,从他们的列表中删除已失效的节点)?这将需要一些昂贵的搜索...

可以避免吗?

谢谢。

4

2 回答 2

4

您有两个选择,即邻接列表和邻接矩阵。前者可能最适合您正在做的事情。要删除一个节点,只需删除该节点所有出边的列表。对于入边,您可以考虑为每个列表保留一个哈希表以进行 O(1) 查找。

这是一个很好的概述 http://www.algorithmist.com/index.php/Graph_data_structures

于 2011-02-22T22:00:58.403 回答
2

我解决了!这是无向图的解决方案,之后添加方向很容易。

在每个顶点中,我都保留了一个特殊的邻接表。它是一个列表(双链接,便于插入/删除),其元素是“槽”:

class Slot {
  Slot prev, next; // pointers to the other slots in the list
  Slot other_end; // the other end of the edge: not a vertex, but a Slot!
  Vertex other_vertex; // the actual vertex at the other end

  void kill() {
    if (next!=null) next.kill(); // recursion
    other_end.pop_out();
  }

  void pop_out() {
    if (next!=null) next.prev = prev;
    if (prev!=null) prev.next = next;
    else other_end.other_vertex.slot_list = next; // in case this slot is the
                                                  // first in its list, I need
                                                  // to adjust the vertex's
                                                  // slot_list pointer.
    // other_end.other_vertex is actually the vertex to which this slot belongs;
    // but this slot doesn't know it, so I have to go around like this.
  }

}

所以基本上每条边都由两个插槽表示,彼此交叉。每个顶点都有一个这样的插槽列表。

当一个顶点被杀死时,它会递归地向其插槽列表发送一个“kill”信号。每个插槽通过销毁其 other_end 来响应(从邻居的列表中优雅地弹出,修复后面的 prev/next 指针)。

这样一个顶点加上它的所有边都被删除而不需要任何搜索。我必须付出的代价是内存:我必须保留 4 个指针(prev、next、vertex 和 other_end),而不是 3 个指针(用于常规双链接邻接列表的 prev、next 和 vertex)。

这是基本思想。对于有向图,我只需要以某种方式区分 IN 插槽和 OUT 插槽。可能通过将每个顶点的邻接列表分成两个单独的列表:IN_slot_list 和 OUT_slot_list。

于 2011-02-23T21:28:13.283 回答