更新、更全的《数据结构与算法》的更新网站,更有python、go、人工智能教学等着你:https://www.cnblogs.com/nickchen121/p/11407287.html

一、集合的简化表示

在上一节 集合及运算中,我们对集合使用二叉树表示,如下图所示:

为了使用二叉树,我们在上一节中使用以下代码,构造二叉树:

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

3.1 Input_connection

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

3.2 Check_connection

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

3.3 Check_network

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

四、pta测试

/* 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)\)

除了上述这种情况,会导致树的高度越来越高,如果我们把高树贴在矮树上,那么树高也会快速增长,因此我们应该考虑把矮树贴在高数上。

对于上述问题的解决,我们给出以下两个解决方法,这两种方法统称为按秩归并。

5.1 方法一:树高替代

为了解决上述问题,我们可以把根结点从-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;
}

5.2 方法二:规模替代

为了解决上述问题,我们也可以把根结点从**-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]);
}

总之上述代码干了这三件事:

  1. 先找到根;
  2. 把根变成X的父结点;
  3. 再返回根

因此,路径压缩第一次执行的时间比较长,但是如果频繁使用查找命令,第一次将路径压缩,大大减小树的高度,后续查找速度将大大增加

6.1 路径压缩时间复杂度计算

由于pta并没有严格控制时间限制,使用java这种语言,不使用路径压缩,问题不大,我写这个也只是为了回顾算法,来放松放松,不是为了折腾自己,因此。

给你一个眼神自己体会,给你一个网址亲自体会https://www.icourse163.org/learn/ZJU-93001?tid=1206471203#/learn/content?type=detail&id=1211167097&sm=1,我是懒得研究下图所示了。

小白专场-FileTransfer-c语言实现的更多相关文章

  1. 小白专场-多项式乘法与加法运算-c语言实现

    目录 一.题意理解 二.求解思路 三.多项式的表示 3.1 数组 3.2 链表 四.程序框架搭建 五.如何读入多项式 六.如何将两个多项式相加 七.如何将两个多项式相乘 八.如何将多项式输出 一.题意 ...

  2. 小白专场-多项式乘法与加法运算-python语言实现

    目录 题意理解 解题思路 多项式加法 多项式乘法 完整代码 题意理解 题目: 设计函数分别求两个一元多项式的乘积与和. 输入格式: 输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一 ...

  3. 小白专场-树的同构-c语言实现.md

    目录 一.题意理解 二.求解思路 2.1 二叉树表示 2.2 程序框架搭建 2.3 如何建二叉树 2.4 如何判别两二叉树同构 更新.更全的<数据结构与算法>的更新网站,更有python. ...

  4. 小白专场-是否同一颗二叉搜索树-python语言实现

    目录 一.二叉搜索树的相同判断 二.问题引入 三.举例分析 四.方法探讨 4.1 中序遍历 4.2 层序遍历 4.3 先序遍历 4.4 后序遍历 五.总结 六.代码实现 一.二叉搜索树的相同判断 二叉 ...

  5. 小白专场-树的同构-python语言实现

    目录 一.题意理解 二.求解思路 更新.更全的<数据结构与算法>的更新网站,更有python.go.人工智能教学等着你:<https://www.cnblogs.com/nickch ...

  6. 小白专场-是否同一颗二叉搜索树-c语言实现

    目录 一.题意理解 二.求解思路 三.搜索树表示 程序框架搭建 3.1 如何建搜索树 3.2 如何判别 3.3 清空树 更新.更全的<数据结构与算法>的更新网站,更有python.go.人 ...

  7. 小白专场-堆中的路径-c语言实现

    目录 一.题意理解 二.堆的表示及其操作 三.主程序 更新.更全的<数据结构与算法>的更新网站,更有python.go.人工智能教学等着你:https://www.cnblogs.com/ ...

  8. 小白专场-堆中的路径-python语言实现

    目录 更新.更全的<数据结构与算法>的更新网站,更有python.go.人工智能教学等着你:https://www.cnblogs.com/nickchen121/p/11407287.h ...

  9. 小白专场-FileTransfer-python语言实现

    目录 更新.更全的<数据结构与算法>的更新网站,更有python.go.人工智能教学等着你:https://www.cnblogs.com/nickchen121/p/11407287.h ...

随机推荐

  1. 为什么要用Kubernetes?

    1.前言 第一次接触Kubernetes是在2016年,再一次浏览博文的时候,那是我第一次听到Kubernetes这个名词,也是第一次认识了k8s这么一个东西.后来在慢慢了解它的时候,被它天生高可用. ...

  2. 2014-09~11Removeapp配置篇

    金蝶ERP软件  Windows REMOVEAPP 功能需求:将服务器端金蝶客户端软件直接在本地实现,只需输入服务器密码即可启动该软件 配置需求:可用的金蝶软件,SERVER2008 或更高(必须激 ...

  3. c++自由的转换string和number

    string转数字 #include <string> #include <sstream> //使用stringstream需要引入这个头文件 //模板函数:将string类 ...

  4. [Python] Django框架入门4——深入模板

    说明: 本文主要深入了解模板(templates),主要涉及模板编写步骤.定义模板.模板继承.HTML转义.CSRF等. 一.模板 动态生成HTML.表达外观.实现业务逻辑(view)与显示内容(te ...

  5. eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南

    eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...

  6. mybatis 源码分析(八)ResultSetHandler 详解

    本篇博客就是 myabtis 系列的最后一篇了,还剩 ResultSetHandler 没有分析:作为整个 mybatis 最复杂最繁琐的部分,我不打算按步骤一次详解,因为里面的主要内容就是围绕 re ...

  7. 动态数组& allocator

    问题来源 在编写程序的时候,对数组."二维数组"的分配的删除掌握的不是很清楚,不能正确的进行定义初始化. 以及在使用vector的时候,如何正确的定义及初始化 注意!!! 尽量使用 ...

  8. library not found for -ljpush-ios-3.2.1错误

    很多人在更新pod后报 library not found for -ljpush-ios-3.2.1(举例)错误,这其实是包含版本号类型错误. 究其原因:使用了版本号做库名字,pod升级后 Podf ...

  9. Trace 2018徐州icpc网络赛 思维+二分

    There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xx , yy) ...

  10. 技术漫谈 | 远程访问和控制云端K8S服务器的方法

    对于部署在云端的K8S容器编排系统,可以先通过SSH远程登录到K8S所在主机,然后运行kubectl命令工具来控制K8S服务系统.然而,先SSH登录才能远程访问的二阶段方式,对于使用Linux桌面或者 ...