我解决了!这是无向图的解决方案,之后添加方向很容易。
在每个顶点中,我都保留了一个特殊的邻接表。它是一个列表(双链接,便于插入/删除),其元素是“槽”:
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。