您的位置:首页 > 编程语言 > Java开发

JAVA实践并查集

2016-07-24 13:09 239 查看

前言

并查集类似数学中的集合,如果是两个集合相交,那就把这两个集合合并成一个集合。

社交网络中推荐可能认识的人,可能是类似原理。

二狗子与B是好友{二狗子, B}

B与A是好友{B,A}

两个相交是B

所以合并,{二狗子,B,A}

系统就可能会将B以可能认识的人给二狗子

发现了不错的文章:

参考链接:

http://blog.csdn.net/dm_vincent/article/details/7655764

http://blog.csdn.net/dm_vincent/article/details/7769159

实现功能

来及《啊哈,算法》

擒贼先擒王---并查集的应用
* 小哼的家乡出现多次抢劫事件,强盗人数众多,警察想查清楚到底有几个犯罪团伙是非常困难的,然而还是搜到了一些线索:
* 10个强盗
* 1号强盗与2号强盗是同伙
* 3号强盗与4号强盗是同伙
* 5号强盗与2号强盗是同伙
* 4号-6号
* 2号-6号
* 8号-7号
* 9号-7号
* 1号-6号
* 2号-4号
* 强盗同伙的同伙也是同伙,现在需要查出有几个独立的犯罪集团。

实现检索出独立犯罪集团的个数。


中文版参考

/**
* 思路来自《啊哈,算法》,我作为初学者,只是复述一遍加深印象。
*
* 首先,假设10个强盗互不认识,每个人的BOSS都是自己,我们要找出每个独立犯罪集团的BOSS,及其下属
* 使用一个一维数组 r 存储
*      每个下标代表强盗编号
*      下标对应的值代表其BOSS
*      例如r[2]=5   表示2号强盗的BOSS是5号强盗
*
* 初始状态
*  index:    1  2  3  4  5  6  7  8  9  10
*      r:   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
*
* 然后,我们逐条线索处理。
* 此处我们假设每一对强盗中,第二个服从第一个,如说到9号-7号。则7号服从9号。
*
* 1号-2号:
*          令2号强盗的BOSS为1号
*          r[2] = 1        // Again,每个下标代表强盗编号,下标对应的值代表其BOSS
*
*          index:    1  2  3  4  5  6  7  8  9  10
*              r:   {1, 1, 3, 4, 5, 6, 7, 8, 9, 10}
*
* 3号-4号:
*          令3号强盗的BOSS为4号
*          r[3] = 4
*
*          index:    1  2  3  4  5  6  7  8  9  10
*              r:   {1, 1, 4, 4, 5, 6, 7, 8, 9, 10}
*
* 5号-2号:
*          此处应是令2号强盗的BOSS为5号,然而
*          2号强盗的BOSS已经是1号了,如何解决?
*
*          方法是,既然2号强盗的BOSS是1号,那么5号去收服2号的BOSS 1号强盗 好了。
*          即r[1] = 5
*
*          index:    1  2  3  4  5  6  7  8  9  10
*              r:   {5, 1, 4, 4, 5, 6, 7, 8, 9, 10}
*
* --------------------------------------------------------------------------------------
*          此后,凡是碰需要收服的强盗BOSS另有其人的,都是去找最顶层的BOSS
*
*          例如8号需要收服9号
*          9号的BOSS是6号
*          6号的BOSS是1号
*          那么。8号直接去收服1号即可
*          PPPPPS:寻找BOSS的过程是递归的,在此过程中可以将寻找到的BOSS赋值给每一个经过的下属
*          这样下次找BOSS,可以直接一步到位
*          原本的BOSS寻找: 9号→6号→1号
*          经过BOSS的替换,而可以做到:9号→1号
*          术语貌似叫压缩路径
*
*          另一种情况,
*          r[5] = 5
*          r[2] = 5
*
*          r[3] = 3
*          r[6] = 3
*
*          6号本来的BOSS是3号,但是现在他有新的BOSS 2号强盗
*          即:2号-6号,那该怎么办呢?
*          答案是,让6号的BOSS 3号强盗 归顺5号强盗即可
*          即r[3] = 5
*
*          总结一下并查集的思路:
*          从n个集合中,寻找几个独立不相交的大集合。
*          将相交的小集合合并即可
*          合并的思路是,每次都寻找最顶层的祖先
*          例如因为B公司的业务对A公司当前有帮助(相交)
*          A公司收购B公司(合并)
*          只需要让B公司的CEO归属A公司的CEO,不需要对每个职员都处理
*          但是每次B公司员工寻找B公司CEO时,可能需要辗转好几个上司、上司的上司等
*          此时可以优化B公司的员工跨过上司直接找到B公司的CEO。而B公司的CEO对A公司CEO负责。
*
*/


代码实现

public class UnionFind {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int[] robber = new int[11];
init(robber);
showArray(robber);
int employer, employee;

for (int i = 1; i < robber.length - 1; i++) {
employer = in.nextInt();
employee = in.nextInt();
unionRobber(robber, employer, employee);
}
showArray(robber);
int sum = 0;
for (int i = 1; i < robber.length; i++) {
if (robber[i] == i) {
sum++;
}
}
System.out.println(sum);
}

public static void init(int[] robber) {
for (int i = 1; i < robber.length; i++) {
robber[i] = i;
}
}
public static void showArray(int[] robber) {
for (int i = 1; i < robber.length; i++) {
System.out.print(robber[i] + " ");
}
System.out.println();
}
public static void unionRobber(int[] robber, int employer, int employee) {
//传进来的是小盗贼头目,可能有大BOSS呢,寻找他
int t1 = findBigBoss(robber, employer);
//可能有上司,让上司对大BOSS负责
int t2 = findBigBoss(robber, employee);

//如果我们找到了小盗贼的BOSS
//同时找到了小盗贼头目的BOSS
//并且不是同伙的,那么让小盗贼的BOSS纳入麾下
if (t1 != t2) {
robber[t2] = t1;
}
}
public static int findBigBoss(int[] robber, int pos) {
//如果他的BOSS是自己,不就是大BOSS嘛
if (robber[pos] == pos) {
return pos;
} else {
//寻找他的上级BOSS,寻找过程中压缩路径。即让所有下属直接对顶层BOSS负责
robber[pos] = findBigBoss(robber, robber[pos]);
return robber[pos];
}
}
}


结果

输出:
1 2 3 4 5 6 7 8 9 10
输入:
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
输出:
5 5 5 5 5 5 8 9 9 10
3


结尾一点

首先一开始看的时候还是有点糊涂的,然后就搜到了开头两篇文章,在了解了应用范围之后,忽然就通了。

大概这是抽象能力不足的表现。

复述的过程中,会感觉到对其思想产生了解,写代码能从整体考虑。

首先我要能找任意盗贼的上司

其次我要能把找到的上司告诉那个盗贼,如果不是同一个上司的话

然后就完了。

END

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 并查集