目录html
更新、更全的《数据结构与算法》的更新网站,更有python、go、人工智能教学等着你:http://www.javashuo.com/article/p-zfinzipt-hh.htmljava
在上一节 集合及运算中,咱们对集合使用二叉树表示,以下图所示:python
为了使用二叉树,咱们在上一节中使用如下代码,构造二叉树:算法
/* c语言实现 */ typedef struct{ ElementType Data; int Parent; } SetType; 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,返回-1 for (; S[i].Parent >= 0; i = S[i].Parent); return i; // 找到X所属集合,返回树根结点在数组S中的下标 }
使用二叉树构造集合,Find操做在差的状况下时间复杂度可能为\(O(n^2)\)数组
所以对于任何有限集合的(N个)元素均可以被一一映射为整数 0~N-1。即对于集合 {2, 5, 4, 3} 和 {6, 0, 1} 咱们可使用以下图所示的数组表示:网络
对于上述的数组,咱们可使用以下代码构造:数据结构
/* c语言实现 */ typedef int ElementType; // 默认元素能够用非负整数表示 typedef int SetName; //默认用根结点的下标做为集合名称 typedef ElementType SetType[MaxSize]; SetName Find(SetType S, ElementType X) { // 默认集合元素所有初始化为-1 for (; S[X] >= 0; X = S[X]); return X; } void Union(SetType S, SetName Root1, SetName Root2) { // 这里默认Root1和Root2是不一样集合的根节点 S[Root2] = Root1; }
根据输入样例,以此来判断计算机之间有多少个组成,以下图所示框架
上图动态变化以下图所示:测试
下图为五台计算机之间造成全链接状态,所以当作一个总体:优化
/* c语言实现 */ int main() { 初始化集合; do { 读入一条指令; 处理指令; } while (没结束); return 0; } int main() { SetType S; int n; char in; scanf("%d\n", &n); Initialization(S, n); do { scanf("%c", &in); switch (in) { case 'I': Input_connection(S); break; // Union(Find) case 'C': Check_connection(S); break; // Find case 'S': Check_network(S, n); break; // 数集合的根,判断计算机网络的组成个数 } } while (in != 'S'); return 0; }
/* c语言实现 */ 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); }
/* c语言实现 */ void Check_connection(SetType S) { ElementType u, v; scnaf("%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"); }
/* c语言实现 */ void Check_network(SetType S, 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); }
/* c语言实现 */ typedef int ElementType; // 默认元素能够用非负整数表示 typedef int SetName; //默认用根结点的下标做为集合名称 typedef ElementType SetType[MaxSize]; SetName Find(SetType S, ElementType X) { // 默认集合元素所有初始化为-1 for (; S[X] >= 0; X = S[X]); return X; } void Union(SetType S, SetName Root1, SetName Root2) { // 这里默认Root1和Root2是不一样集合的根节点 S[Root2] = Root1; }
对于上述的代码,若是咱们放入pta中测试,会发现测试点6运行超时,以下图所示:
所以,咱们会考虑是否是由于出现了某种状况,致使Root2为根结点的树过大了,所以咱们修改代码为:
/* c语言实现 */ typedef int ElementType; // 默认元素能够用非负整数表示 typedef int SetName; //默认用根结点的下标做为集合名称 typedef ElementType SetType[MaxSize]; SetName Find(SetType S, ElementType X) { // 默认集合元素所有初始化为-1 for (; S[X] >= 0; X = S[X]); return X; } void Union(SetType S, SetName Root1, SetName Root2) { // 这里默认Root1和Root2是不一样集合的根节点 // S[Root2] = Root1; S[Root1] = Root2; }
发现更换代码后,测试点5却运行超时了,为了解决上述问题,咱们可使用下面将要讲到了按秩归并的思想修改代码。
为何须要按秩归并呢?由于咱们使用pta测试程序,发现代码老是超时,所以咱们能够考虑是否出现这种状况——咱们再不断地往一颗树上累加子树,以下图所示:
/* c语言实现 */ Union(Find(2), Find(1)); Union(Find(3), Find(1)); ……; Union(Find(n), Find(1));
从上图能够看出,此过程的时间复杂度为:\(T(n) = O(n^2)\)
除了上述这种状况,会致使树的高度愈来愈高,若是咱们把高树贴在矮树上,那么树高也会快速增加,所以咱们应该考虑把矮树贴在高数上。
对于上述问题的解决,咱们给出如下两个解决方法,这两种方法统称为按秩归并。
为了解决上述问题,咱们能够把根结点从-1替代为-树高,代码以下:
/* c语言实现 */ if ( Root2高度 > Root1高度 ) S[Root1] = Root2; else { if ( 二者等高 ) 树高++; S[Root2] = Root1; } if ( S[Root2] < S[Root1] ) S[Root1] = Root2; else { if ( S[Root1]==S[Root2] ) S[Root1]--; S[Root2] = Root1; }
为了解决上述问题,咱们也能够把根结点从**-1替代为-元素个数(把小树贴到大树上),代码以下:
/* c语言实现 */ void Union( SetType S, SetName Root1, SetName Root2 ) { if ( S[Root2]<S[Root1] ){ S[Root2] += S[Root1]; S[Root1] = Root2; } else { S[Root1] += S[Root2]; S[Root2] = Root1; } }
对于上述代码超时的问题,咱们也可使用路径压缩的方法优化代,即压缩给定元素到集合根元素路径中的全部元素,详细状况以下图所示:
上图代码可表示为:
/* c语言实现 */ SetName Find(SetType S, ElementType X) { // 找到集合的根 if (S[X] < 0) return X; else return S[X] = Find(S, S[X]); }
总之上述代码干了这三件事:
所以,路径压缩第一次执行的时间比较长,可是若是频繁使用查找命令,第一次将路径压缩,大大减少树的高度,后续查找速度将大大增长
因为pta并无严格控制时间限制,使用java这种语言,不使用路径压缩,问题不大,我写这个也只是为了回顾算法,来放松放松,不是为了折腾本身,所以。
给你一个眼神本身体会,给你一个网址亲自体会https://www.icourse163.org/learn/ZJU-93001?tid=1206471203#/learn/content?type=detail&id=1211167097&sm=1,我是懒得研究下图所示了。