数据结构与C语言实现(七)——树(下):集合与集合例题

来源:互联网 发布:淘宝 lolita布料 编辑:程序博客网 时间:2024/06/14 00:46

首先是集合的基本数据类型,这里的查找我使用了规模对比的优化方式。

//用树实现集合的表现形式,注意是树不是二叉树,这是一种包含指向爸爸下标的数据结构#include <stdio.h>#include <stdlib.h>#define MaxSize 100typedef struct{int data;int parent;//负数表示为集合首个元素(即根节点),绝对值为数量}SetType;SetType S[10];//假设有10个元素//查找某个元素所在的集合int Find(SetType S[], int X){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);//不断地向上找爸爸,直到发现爸爸值为-1return i;//找到X所属的集合,返回树根节点的数组S中的下标}//用for循环真的反人类,不如while舒服,这里用while写一下int FindWhile(int item,SetType S[]){int i;while (S[i].data != item) i++;//先找到iwhile (S[i].parent >= 0) i = S[i].parent;//向上找爸爸,直到爸爸小于0return i;//集合首元素}//集合的并运算/*1.找到元素所在的根节点2.然后将一个树的parent指向另一个树即可*/void Union(SetType S[], int X1, int X2){int Root1, Root2;Root1 = FindWhile(X1, &S[MaxSize]);//但是擅长指针的你,为什么不写成下面这种形式呢Root2 = FindWhile(X2, S);if ((Root1 != Root2) && (-Root1 > -Root2))//root1的数量比root2的数量多{Root1 = Root1 + Root2;//将头合并为两个负数的和S[Root2].parent = Root1;}else{Root2 = Root1 + Root2;//将头合并为两个负数的和,注意我这里用的是按照规模归并S[Root1].parent = Root2;}将一个集合的头指向另一个集合的父亲,那么现在roo1就是并集之后的集合首元素}/*为了查找的方便,我们希望能够把小的,元素少的集合并到大的,元素多的集合。那么,我们可以不把parent统一规定为-1.可以规定为数量的负数。*/

下面是一道堆的例题,采用了一种新的数据结构形式。

/*集合的简化表示方法1.我们将数量可数的元素映射到0到N-12.然后建立数组A[N],下标表示的是元素的data,数组中存放的内容是parent的值*/#include <stdio.h>#include <stdlib.h>#define MaxSize 1000typedef int ElementType;typedef int SetName;typedef ElementType SetType[MaxSize];//比如说 int S[100] 可以用 SetType SSetName Find(SetType S, ElementType X){while (S[X] > 0)//父节点大于0,代表不是集合首元素{X = S[X];//S[X]代表的是父节点,赋值给X那么再S[X],就相当于是父亲的父亲}return X;//直到找到S[X]<0的,那么就返回数据X,X的值就是集合首元素的值}//路径压缩下的FindSetName FindRar(SetType S, ElementType X){if (S[X] < 0) return X;elsereturn S[X] = Find(S, S[X]);//这句话做了三件事,1.先找到根2.把根变成X的父节点3.再返回根}//按秩归并//一多一少,高度不变,同样高度的归并,高度++;void Union(SetType S, SetName Root1, SetName Root2){//显然Root1代表的是S下标,同时表示数据//两个集合的并只需要把一个的S[X]指向另一个if(-S[Root2] > -S[Root1])//如果树2比树1高,那么树二就是合并后的树S[Root1] = Root2;else{if (S[Root1] == S[Root2])S[Root1]--;S[Root2] = Root1;}//S[Root2]指的是Root2这个值的爸爸,原来是-1,后来变成了Root1}void Init(SetType S, ElementType num){for (int i = 0; i < num; i++)S[i] = -1;}/*题目:File Transfer5五台计算机C 3 2   3和2之间能联通吗?I 3 2   将3和2连接在一起C 1 51和5能联通吗? I 4 5I 2 4C 3 5S       退出然后输出系统中有几个联通集*/void Input_connection(SetType S){ElementType com1, com2;scanf("%d %d", &com1, &com2);int Root1 = Find(S, com1 - 1);int Root2 = Find(S, com2 - 1);if(Root1 != Root2)Union(S, Root1, Root2);printf("%d 和 %d  现在连接在了一起\n ",com1,com2);}void Check_connection(SetType S){ElementType com1, com2;scanf("%d %d", &com1, &com2);if (Find(S, com1 - 1) == Find(S, com2 - 1))printf("能够连通\n");elseprintf("不能够连通\n");}void Check_networks(SetType S,int com_num){int num = 0;for (int i = 0; i < com_num; i++){if (S[i] < 0) num++;}printf("目前有 %d 个连通区域\n",num);}int main(){SetType S;int computer_num = 0;char in = 0;printf("请告诉我一共有多少台电脑\n");scanf("%d", &computer_num);Init(S, computer_num);do{scanf("%c", &in);switch (in){case 'I':Input_connection(S); break;case 'C':Check_connection(S); break;case 'S':Check_networks(S,computer_num); break;default:break;}} while (in != 'S');//只要输入的字符不等于S,那么就这么循环return 0;}


阅读全文
0 0