并查集的理解和实现

题出问题:

前提:有1,2,3,4,5五点,2和3,3和4相通。

问1:5和1是否相通?

问2:如何使5个点全部相通?

在这里插入图片描述

并查集

1.介绍

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

这里用并查集解决连通之类的问题会更加简单,为了便于理解,在这里用数组来做简单的并查集。

2.实现代码

这里就不废话了,代码贴上来也不用看那麽多字。

int pre[1000 ];
int find(int x)                                       //查找根节点
{ 
    int r=x;
    while ( pre[r] != r )                           //返回根节点 r,因为只有根结点的值和下标是相                                                      同的
          r=pre[r];

int i=x , j ;
while( i != r )                                   //路径压缩,把记录的父节点直接变成根结点
{
     j = pre[ i ]; 				// 在改变上级之前用临时变量  j 记录下他的值 
     pre[ i ]= r ; 				//把上级改为根节点
     i=j;
}
return r ;

}

void join(int x,int y)                           //判断x y是否连通,
                                               //如果已经连通,就不用管了 如果不连通,就把它们所                                                  在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx]=fy;
}
3.在这里简单的解释下

这里的并查集实现主要是用数组来模拟,然后进行操作。真实的是树结构,有兴趣的可以继续研究。

这里的数组的下标对应的是图的第几个节点,值代表当前的节点的父节点的位置。

当然在压缩路径之后父节点都是根结点。这里便于搜索,否则出现了一字长蛇阵搜索就是很浪费时间。

在这里插入图片描述

这里就可以得出了前面的答案:

1.搜索两点是否连通时,只要看两者父节点是否相同,也就是值是否相同。

2.连通时,只要包根结点连接,就是调用jion方法即可。

join时这里可以随便的连接根结点,但是在树中,要把深度低的树加到深度高的树,这样总体的树的深度不会增长。

简单的并查集题目

2015年第五届ACM趣味编程循环赛(第一场) by LeiQ
Problem Description
小雷有个特殊的癖好,平时喜欢收藏冰茶几!
顾名思义,这些茶几被冰冻住了,因此一套冰茶几分为好几部分,并且如果茶几A与B冻在一起,B与C冻在一起,那么A与C也就冻在了,即冰冻状态有传递性,ABC此时会看作一个整体。
为了保证冰茶几的完整性,小雷每次只能移动一整块冰茶几,也就是冰冻在一起的一部分。小雷想知道他需要搬几次才能全部搬到实验室,你能帮小雷快速计算出答案么?

Input
多组输入,先输入组数T(1 < = T < = 200)。
对于每组输入,先输入一个整数n(1 < = n < = 100000),k(0 < = k < = 100000),总共有n个茶杯,茶几编号1~n。
之后k行,每行两数x,y(1 < = x,y < = n),表示第x个茶几和第y个茶几冰冻在一起。

Output
对于每组输入,先输出”Case z: ”(不带引号)表示组数,再输出一个整数,表示小雷需要搬动的次数。

Sample Input
3
3 1
1 2
5 2
1 2
3 4
5 2
1 2
2 3

Sample Output
Case 1: 2
Case 2: 3
Case 3: 3

简单的代码实现,有兴趣的同学可以优化一下时间。

void join(int x,int y)                           //判断x y是否连通,
                                           //如果已经连通,就不用管了 如果不连通,就把它们所                                                  在的连通分支合并起,
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
        pre[fx]=fy;
}
  public static int select(int[] arr) {
            int sum = 0;
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] == i) {
                    sum++;
                }
            }
            return sum;
        }
    
        public static void main(String[] args) {
            int group;  //输入的组数
            Scanner input = new Scanner(System.in);
            group = input.nextInt();
            int count = 1;
            while (count <= group) {
                int number = input.nextInt();
                int key = input.nextInt();
                int[] arr = new int[number + 1];
                for (int i = 1; i < number; i++)
                    arr[i] = i;
                while (key != 0) {
                        int x = input.nextInt();
                        int y = input.nextInt();
                        join(x,y)
                       key--;
                }
                System.out.println("Case " + count + ": " + select(arr));
                count++;
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值