什么是并查集
有多个集合,集合内有多个元素
并查集算法用来查找一个元素所属的集合,合并两个元素各自所属的集合。称为并查集
算法举例
亲戚关系的等价问题,犯罪团伙的头目。
给出很多人的亲戚相互间关系,查找任意两人是否为亲戚。
多个犯罪分子各自在自己的团伙中,找到犯罪团伙的数量。
算法思路
使用树的数据结构来实现并查集算法。
关键点:
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为元素个数