思路:结构体数组表示
typedef struct treenode{
int data;
int parent;
}tree;
数组中每个元素都是一个结构体,一个分量存该节点数值int data;
,另一个分量int parent;
存父结点的数组下标,实现了通过孩子结点找父结点的操作。
特别的,对于根结点,不再有父结点,故分量int parent;
设为-1.
在优化并入操作时,我们希望有一个分量可以记录集合大小,这样能轻松实现将小的集合并入大的集合。对于这个特殊的分量,实际上只要根结点需要,所以我们把根结点的int parent;
分量的大小设为负数(表示其没有父结点),绝对值设为集合元素个数。比如一个结点的int parent;
为-7,代表这个结点时根结点,并且该集合中有7个元素。
操作集:
int find(tree set[],int X,int Maxsize)
查找两个元素是否在一个集合
tree combine(tree set[],int m,int n)
将两个元素并入一个集合
tree Union(tree set[],int m,int n)
为避免随机并入元素时出现长蛇怪等现象导致树高不可控,find函数效率下降严重,我们优化并入操作,使大的集合并入小的集合
int Find( tree *S, int X )
路径压缩
代码实现:
1.查找和并入
#include<stdio.h>
#include<malloc.h>
typedef struct treenode{
int data;
int parent;
}tree;
int find(tree set[],int X,int Maxsize)//Maxsize为集合中总元素的个数
{
int i=0;
while(i<Maxsize)
{
if(X==set[i].data)
break;
i++;
}
if(i == Maxsize)//由于没有找到而退出while循环
return -1;
else//找到了
{
while(set[i].parent >= 0)//当找到的结点不是根结点
{
i=set[i].parent;//向上移动,直到根结点
}
return i;
}
}
tree combine(tree set[],int m,int n)
{
int root1,root2;
root1 = find(set,m,10000);//先找到两个元素对应的根结点
root2 = find(set,n,10000);
if(root1 != root2)//若根结点不一样,就随机把一个树的根结点的父亲设为另外一个树的根结点
{
set[root2].parent=root1;
return *set;
}
}
2.优化后的并入操作
tree Union(tree set[],int m,int n)
{
int root1,root2;
root1 = find(set,m,10000);
root2 = find(set,n,10000);
if(root1!=root2)//当两个集合不同时
{
if(set[root1].parent<set[root2].parent)//集合1比集合2大
{
set[root2].parent=root1;
set[root1].parent=set[root1].parent + set[root2].parent;
return *set;
}
else//集合2比集合1大
{
set[root1].parent=root2;
set[root2].parent=set[root1].parent + set[root2].parent;
return *set;
}
}
}
3.路径压缩
int Find( tree *S, int X )
{ /* 默认集合元素全部初始化为-1 */
if ( S[X].data < 0 ) /* 找到集合的根 */
return X;
else
return S[X].parent = Find( S, S[X].data ); /* 路径压缩 */
}