并查集--求解等价问题

什么是并查集

有多个集合,集合内有多个元素
并查集算法用来查找一个元素所属的集合,合并两个元素各自所属的集合。称为并查集

算法举例

亲戚关系的等价问题,犯罪团伙的头目。
给出很多人的亲戚相互间关系,查找任意两人是否为亲戚。
多个犯罪分子各自在自己的团伙中,找到犯罪团伙的数量。

算法思路

使用树的数据结构来实现并查集算法。

关键点:
1. 初始化集合,刚开始每个元素为一个集合,该元素就代表了该集合;如果有多个元素,根元素代表一个集合。根节点的parent指针指向自己。(元素间虽然有父子关系但是不意味者有从属关系,只是起到联系集合元素的作用)
2. 查找一个元素所属的集合。找该元素所在集合的根节点。
3. 合并集合。为了使合并后的树的高度更小,需要将高度较小的树作为高度较大的树的子树。若两树的高度相等需要将高度+1;

算法实现

java实现

package aha_algorithm;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class MergeSearchSet {


    public static class MSSNode{
        int id;//元素编号
        int rank;//树的高度称为秩
        int parent;//父节点下标
    }

    static int elementNum;
    static int relationNum;

    static MSSNode[] MSSTree;

    /**
     * @param args
     */
    public static void main(String[] args) {
        initSet();
        judgeRelation();
    }

    public static void initSet(){
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

        try {
            String[] inLine = input.readLine().split(" ");

            elementNum= Integer.valueOf(inLine[0]);
            relationNum = Integer.valueOf(inLine[1]);

            MSSTree = new MSSNode[elementNum];
            //初始化关系树
            for (int i = 0; i < elementNum; i++) {
                MSSNode tempNode = new MSSNode();
                tempNode.id=i;
                tempNode.rank=0;
                tempNode.parent=i;

                MSSTree[i]= tempNode;
            }

            //获取关系并 合并
            for (int i = 0; i < relationNum; i++) {
                String[] relation = input.readLine().split(" ");

                int idLeft= Integer.valueOf(relation[0]);
                int idRight = Integer.valueOf(relation[1]);
                mergeSet(idLeft, idRight);
            }



        }catch(Exception e){
            e.printStackTrace();
        }
    }

    static int findSet(int id){
        if(id == MSSTree[id].parent){
            return id;
        }
        return findSet(MSSTree[id].parent);
    }

    static void mergeSet(int idLeft,int idRight){
        int parentLeft = findSet(idLeft);
        int parentRight = findSet(idRight);

        if(MSSTree[parentLeft].rank < MSSTree[parentRight].rank){
            MSSTree[parentLeft].parent = parentRight;
        }else{
            MSSTree[parentRight].parent = parentLeft;
            if(MSSTree[parentLeft].rank == MSSTree[parentRight].rank){
                MSSTree[parentLeft].rank++;
            }
        }
    }

    static void judgeRelation(){
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

        try {
            String[] inLine = input.readLine().split(" ");
            int id1, id2;

            id1 = Integer.valueOf(inLine[0]);
            id2 = Integer.valueOf(inLine[1]);
            if(findSet(id1)==findSet(id2)){
                System.out.println(id1+"和"+id2+"是亲戚");
            }else{
                System.out.println(id1+"和"+id2+"不是亲戚");
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

时间复杂度

主要时间在查找元素所在的集合即找根节点。所有时间复杂度为logN。N为元素个数

你可能感兴趣的:(数据结构与算法)