首先,我得到了一个N * N距离矩阵,对于每个点,我计算了它的最近邻居,所以我们有一个N * 2矩阵,看起来像这个:
0 -> 1 1 -> 2 2 -> 3 3 -> 2 4 -> 2 5 -> 6 6 -> 7 7 -> 6 8 -> 6 9 -> 8
第二列是最近邻居的索引。所以这是一种特殊的指导 图,每个顶点都有,只有一个出度。
当然,我们可以先将N * 2矩阵转换为标准图形表示,然后执行BFS / DFS以获取连接的组件。
但是,鉴于这个特殊图表的特点,还有其他快速的方法来完成这项工作吗?
我将非常感激。
更新
我为此案例 here实施了一个简单的算法。
看,我没有使用union-find算法,因为数据结构可能会让事情变得不那么容易,我怀疑它是否是我案例中最快的方法(我的意思是实际上)。
你可能会认为_merge过程可能很耗时,但是如果我们在分配新标签时将边缘交换到连续位置,则合并可能成本很低,但需要另外N个空格来跟踪原始索引。
答案 0 :(得分:4)
在给定边缘列表的情况下查找连通分量的最快算法是union-find算法:对于每个节点,保持指向同一集合中节点的指针,如果找到所有边缘会聚到同一节点一条长度至少为2的路径,向上重新连接底部节点。
这肯定会在线性时间内运行:
- push all edges into a union-find structure: O(n)
- store each node in its set (the union-find root)
and update the set of non-empty sets: O(n)
- return the set of non-empty sets (graph components).
由于边缘列表已经几乎形成了一个联合查找树,因此可以跳过第一步:
for each node
- if the node is not marked as collected
-- walk along the edges until you find an order-1 or order-2 loop,
collecting nodes en-route
-- reconnect all nodes to the end of the path and consider it a root for the set.
-- store all nodes in the set for the root.
-- update the set of non-empty sets.
-- mark all nodes as collected.
return the set of non-empty sets
第二种算法也是线性的,但只有一个基准测试才能判断它是否真的更快。 union-find算法的优势在于其优化。这将优化延迟到第二步,但完全取消了第一步。
如果您使用最近邻居计算加入联合步骤,则可能会挤出更多性能,然后在第二遍中收集集合。
答案 1 :(得分:1)
由于每个节点只有一个传出边,因此您可以一次遍历图一个边,直到到达已经访问过的顶点。超度为1意味着此时任何进一步的遍历只会带你去过你已经去过的地方。该路径中的遍历顶点都在同一个组件中。
在你的例子中:
0->1->2->3->2, so [0,1,2,3] is a component
4->2, so update the component to [0,1,2,3,4]
5->6->7->6, so [5,6,7] is a component
8->6, so update the compoent to [5,6,7,8]
9->8, so update the compoent to [5,6,7,8,9]
您可以只访问每个节点一次,因此时间为O(n)。空间是O(n),因为您只需要每个节点的组件ID和组件ID列表。
答案 2 :(得分:1)
如果你想按顺序进行,你可以使用加权快速联合和路径压缩.Complexity O(N + Mlog(log(N)))。检查此链接。 这是伪代码.honoring @pycho的话
`
public class QuickUnion
{
private int[] id;
public QuickUnion(int N)
{
id = new int[N];
for (int i = 0; i < N; i++) id[i] = i;
}
public int root(int i)
{
while (i != id[i])
{
id[i] = id[id[i]];
i = id[i];
}
return i;
}
public boolean find(int p, int q)
{
return root(p) == root(q);
}
public void unite(int p, int q)
{
int i = root(p);
int j = root(q);
id[i] = j;
}
}
` @reference https://www.cs.princeton.edu/~rs/AlgsDS07/01UnionFind.pdf
如果要并行查找连通分量,可以使用指针跳转和路径压缩加权快速联合将渐近复杂度降低到O(log(log(N))时间。检查此链接