file transfer(文档传送程序)-并查集的应用

/*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]); 
} 
 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值