并查集--求解等价问题

来源:互联网 发布:matlab求矩阵的相角 编辑:程序博客网 时间:2024/05/29 07:10

什么是并查集

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

算法举例

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

算法思路

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

关键点:
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为元素个数