并查集算法总结

并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。主要就是判断两个元素是否连通。

每个集合可能包含一个或多个元素,选出集合中的某个元素作为代表。每个集合中具体包含了哪些元素是无所谓的,具体选择哪个元素作为代表一般也是无所谓的。我们关心的是,对于给定的元素,可以很快的找到这个元素所在的集合(的代表),以及合并两个元素所在的集合。

并查集通过一个一维数组来实现,其本质是维护一个森林。刚开始的时候,森林的每个点都是孤立的,也可以理解为每个点就是一棵只有一个结点的树,之后通过一些条件,逐渐将这些树合并成一棵大树。其实合并的过程就是“认爹”的过程。在“认爹”的过程中,要遵守“靠左”原则和“擒贼先擒王”原则。在每次判断两个结点是否已经在同一棵树中的时候(一棵树其实就是一个集合), 也要注意必须求其根源,中间父亲结点(“小BOSS”)是不能说明问题的,必须找到其祖宗( 树的根结点),判断两个结点的祖宗是否是同一个根结点。

核心代码:

//这是找爹的递归函数,不停地去找爹,直到找到祖宗为止,”擒贼先擒王”原则
int find(int v) {
    if (f[v] == v)
        return v;
    //这里是路径压缩,每次在函数返回的时候,顺带把路上遇到的人的"BOSS"改为最后找到的祖宗编号。这样可以提高今后找到树的祖先的速度。
    return f[v] = find(f[v]);
}
//这里是合并两子集合的函数
void merge(int v, int u) {
    int t1, t2; //t1、t2分别为v和u的大Boss,每次双方的会谈那必须是各自最高领导人才行
    t1 = find(v);
    t2 = find(u);
    if (t1 != t2) //判断两个结点是否在同个集合中,即是否为同一个祖先。
        f[t2] = t1;
    //"靠左"原则,左边变成右边的BOSS。即把右边的集合,作为左边集合的子集合。经过路径压缩以后,将f[u]的根的值也赋值为v的祖先f[t1]。
}