集合的并查

来源:互联网 发布:java ocr身份证识别 编辑:程序博客网 时间:2024/04/23 21:47

所谓集合的并查主要是指两种运算,并(把两个集合并在一起)和查(查找某个元素是属于什么集合的),这里有一个经典题目

例子:有10台电脑{1,2,3,...,9,10},已知下列电脑之间已经实现了连接:

        1和2,2和4,3和5,4和7,5和8,6和9,6和10

问:2和7之间,5和9之间是否是联通的?


解决思路:

(1)将10台电脑看成10个集合{1},{2},{3},...,{9},{10}

(2)已知一种连接“x和y”,就将x和y对应的集合合并;

(3)查询“x和y是否是连通的”就是判别x和y是否属于同一集合


有一种方法是用集合中的某个元素作为树根,其他元素作为叶子结点,例如


并的时候只要把其根挂在另一个根下就好,这种表示方法叫做双亲表示法,也就是孩子指向其父亲

两个函数分别为

//查找某个元素所在的集合(用根节点表示)int Find(SetType S[],ElementType X){//在数组S中查找值为X的元素所属的集合//MaxSize是全局变量,为数组S的最大长度int i;for(i=0;i<MaxSize&&S[i].Data!=X;i++);if(i>=MaxSize) return -1;//未找到X,返回-1for(;S[i].Parent>=0;i=S[i].Parent);return i;};//集合的并运算void Union(SetType S[],ElementType X1,ElementType X2){int Root1,Root2;Root1=Find(S,X1);Root2=Find(S,X2);if(Root1!=Root2)S[Root2].Parent=Root1;};
下面对如下图所示的举例

首先是查找结点10和3的根,然后将两个集合合并,再次找其根节点

执行结果是



附上完整代码

#include <stdio.h>    #include <stdlib.h>    #define MaxSize 100 typedef int ElementType;typedef struct{ElementType Data;int Parent;//父节点的下标}SetType;//查找某个元素所在的集合(用根节点表示)int Find(SetType S[],ElementType X);//集合的并运算void Union(SetType S[],ElementType X1,ElementType X2);int main(){     SetType S[MaxSize];   int a[10]={1,2,3,4,5,6,7,8,9,10};   int b[10]={-1,0,-1,0,2,-1,0,2,5,5};     for(int i=0;i<MaxSize;i++){   S[i].Data=S[i].Parent=-1;   }   for(int i=0;i<10;i++){    S[i].Data=a[i];S[i].Parent=b[i];   }     printf("10在的根节点为%d\n",Find(S,10)+1);   printf("3在的根节点为%d\n",Find(S,3)+1);   printf("\n");   Union(S,10,3);   printf("10在的根节点为%d\n",Find(S,10)+1);   printf("3在的根节点为%d\n",Find(S,3)+1);    system("pause");  }//查找某个元素所在的集合(用根节点表示)int Find(SetType S[],ElementType X){//在数组S中查找值为X的元素所属的集合//MaxSize是全局变量,为数组S的最大长度int i;for(i=0;i<MaxSize&&S[i].Data!=X;i++);if(i>=MaxSize) return -1;//未找到X,返回-1for(;S[i].Parent>=0;i=S[i].Parent);return i;};//集合的并运算void Union(SetType S[],ElementType X1,ElementType X2){int Root1,Root2;Root1=Find(S,X1);Root2=Find(S,X2);if(Root1!=Root2)S[Root2].Parent=Root1;};
这样做就是会出现一个问题,有可能会把高的树挂在低的树下面,树越来越大的同时也会越来越高,所以会导致Find效率会降低,为了改善合并以后的查找性能,可以采用小的集合合并到相对大的集合中,正好可以修改根节点原本的-1的值,表示其下面挂了几个元素,修改后的Union函数为

//集合的并运算void Union(SetType S[],ElementType X1,ElementType X2){int Root1,Root2;Root1=Find(S,X1);Root2=Find(S,X2);if(Root1!=Root2){if(S[Root1].Parent<S[Root2].Parent){S[Root2].Parent=Root1;S[Root1].Parent+=S[Root2].Parent;}    else {S[Root1].Parent=Root2;S[Root2].Parent+=S[Root1].Parent;}}};
哈哈哈哈哈,done

1 0
原创粉丝点击