/*file transfer文档传送程序*/
typedef struct{//本数组的类型是结构体。集合的每个元素直接用数组里的下标去代表即可,此时数据域可以不要,直接定义一个整型数组即可表示集合。
ElementType Data;//数组有个结构域Data对应的是集合的元素的具体类型 (任何想要的类型)
int Parent;//是个指针记录元素在数组里父结点的位置
}SetType;
SetType S[];
int Find(SetType S[],ElementType X)
{
int i;
//计算机从1~N编号,Data就成了整数。N个整数有必要开个数据域Data存它吗?
for(i=0;i<MaxSize&&S[i].Data!=X;i++);/*找X是集合中是第几个元素 。首先要在数组里找到它(线性扫描过程),
最坏情况是找数组里最后一个元素,反复找N遍,如果集合里有N个元素,把第N个反复找N遍。*/
//想知道集合元素X属于哪个集合。最坏情况时间复杂度为O(N*N),有点慢
if(i>MaxSize) return -1;
for( ;S[i].Parent>=0;i=S[i].Parent);//从此位置检查它的父结点,>=0一直往上找,找到父结点为-1,返回i为根结点的下标
return i;
}//每个元素对应的是数组的下标。例0结点父为6,所以S[0]=6
typedef int ElementType;//集合的简化表示。默认元素可以用非负整数表示(0~N-1)
typedef int SetName;//默认用根结点的下标作为集合名称
typedef ElementType SetType[MaxSize];//集合的类型是一个整型数组
SetName Find(SetType S,ElementType X)//简化后的Find函数
{//默认集合元素全部初始化为-1
for( ;S[X]>=0;X=S[X]) ;//S[X]是存放父结点,找到父结点为-1,返回X为根结点的下标
return X;
}//查找元素X在哪里,先不需要扫描整个数组找到X,因为X是数组下标。
void Union(SetType S,SetName Root1,SetName Root2)
{//这里默认Root1和Root2是不同集合的根结点/而判断参数合法性交给用户做
S[Root2]=Root1;
}
int main()
{
SetType S;//这是并查集,需要一个集合
int n;//是集合的元素个数
char in;//读每条指令,这条指令关键是第一个字符命名为in
scanf("%d\n",&n);
Initialization(S,n);//调用这个函数把S做初始化。
do{
scanf("%c\n",&in);//判断是哪种指令,直到in!='S'('S'是个终止符号)
switch(in){
case 'I': Input_connection(S); break;
case 'C': Check_connection(S); break;
case 'S': Check_network(S,n); break;
}
}while(in!='S');
return 0;
}
void Input_connection(SetType S)//输入指令
{
ElementType u,v;
SetName Root1,Root2;
scanf("%d %d\n",&u,&v);
Root1=Find(S,u-1);
Root2=Find(S,v-1);
if(Root1!=Root2)
Union(S,Root1,Root2);
}
void Check_connection(SetType S)//查询指令
{
ElementType u,v;
SetName Root1,Root2;
scanf("%d %d\n",&u,&v);
Root1=Find(S,u-1);
Root2=Find(S,v-1);
if(Root1==Root2)
printf("yes\n");
else printf("no\n");
}
void Check_network(SetTypeS,int n)//判断整个网络是否联通指令
{
int i,counter=0;
for(i=0;i<n;i++){
if(S[i]<0) counter++;
}
if(counter==1)
printf("The network is connected.\n");
else
printf("There are %d components.\n",counter);
}
/*按秩归并(1.按树高度2.按树规模)*/
void Union_height(SetType S,SetName Root1,SetName Root2)//比树高
{//S[Root]=-树高;
if(S[Root2]<S[Root1])//负数的比较
S[Root1]=Root2;
else{
if(S[Root1==Root2]) S[Root1]--;//正值+1,意味负值-1
S[Root2]=Root1;
}
}//最坏情况下的树高时间复杂度=O(logN)
void Union_scale(SetType S,SetName Root1,SetName Root2)//比规模
{//S[Root]=-元素个数;
if(S[Root2]<S[Root1]){//因为存的是负数
S[Root2]+=Root1;//所以把集合2大小做改变,加上原来的集合1的规模
S[Root1]=Root2;//集合1指向集合2
}
else{
S[Root1]+=Root2;
S[Root2]=Root1;
}
}//最坏情况下的树高时间复杂度=O(logN)
/*路径压缩(对find函数优化)*/
SetType Find(SetType S,ElementType X)
{
if(S[X]<0)//找到集合的根
return X;
else
return S[X]=Find(S,S[X]);
}