C语言:森林与并查集

两种考察连通性的算法:

  • Quick_find算法:将所有元素的代表元素设为后面merge的元素,最后会呈现出表格中有几个元素就有几类的情况,但每次更新权值都要进行所有元素的搜索,很慢。
  • Quick_union算法:将每个集合的代表元素改成一样的,比如2->1,那么将2与3并时,只需将1->3。判断是否属于一个集合需要递归找到自己就是代表元素的节点,就是这个集合的根结点,此时也是,有几个集合就有几个树。

Quick_union优化:

  • 根据权值(子节点数量)决定谁是爸爸
  • 路径压缩:在搜索代表节点时,找如果不是直接挂在根上的,就把他的直系父亲节点改为根。
#include <stdio.h>
#include <stdlib.h>

typedef struct UnionSet{
    int *color;
    int *size;//记录每个节点下子节点个数
    int n;
}UnionSet;

UnionSet *init(int n){
    UnionSet *u = (UnionSet *)malloc(sizeof(UnionSet));
    u->color = (int *)malloc(sizeof(int) * (n + 1));
    u->size = (int *)malloc(sizeof(int) * (n + 1));
    u->n = n;
    for (int i = 0; i < n; i++){
        u->color[i] = i;
        u->size[i] = 1;
    }
    return u;
}

int find(UnionSet *u, int x){
    return u->color[x] = (u->color[x] == x ? x : find(u, u->color[x]));
}

int merge(UnionSet *u, int a, int b){
    int fa = find(u, a), fb = find(u, b);
    if (fa == fb) return 0;
    if (u->size[fa] > u->size[fb]){
        int t = fa;
        fa = fb;
        fb = t;
    }
    //int color_a = u->color[a];//要多设一个变量不然中途会变
    // for (int i = 0; i < u->n; i++){
    //     if (u->color[i] == color_a){
    //         u->color[i] = u->color[b];
    //         u->size[b] += u->size[a];
    //     }
    // }
    u->color[fa] = fb;
    u->size[fb] += u->size[fa];
    return 1;
}


int main(){
	int n, m;
	scanf("%d%d", &n, &m);
	UnionSet *u = init(n);
	for (int i = 0; i < m; i++){
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		switch(a){
		case 1:merge(u, b, c);break;
		case 2:printf("%s\n", find(u, b)==find(u, c) ? "YES" : "NO");
		}
	}
	return 0;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页