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

一、集合的简化表示

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

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

  1. /* c语言实现 */
  2. typedef struct{
  3. ElementType Data;
  4. int Parent;
  5. } SetType;
  6. int Find(SetType S[], ElementType X)
  7. {
  8. // 在数组S中查找值为X的元素所属的集合
  9. // MaxSize是全局变量,为数组S的最大长度
  10. int i;
  11. for (i = 0; i < MaxSize && S[i].Data != X; i++);
  12. if (i >= MaxSize) return -1; // 未找到X,返回-1
  13. for (; S[i].Parent >= 0; i = S[i].Parent);
  14. return i; // 找到X所属集合,返回树根结点在数组S中的下标
  15. }

使用二叉树构造集合,Find操作在差的情况下时间复杂度可能为\(O(n^2)\)

因此对于任何有限集合的(N个)元素都可以被一一映射为整数 0~N-1。即对于集合 {2, 5, 4, 3} 和 {6, 0, 1} 我们可以使用如下图所示的数组表示:

对于上述的数组,我们可以使用如下代码构造:

  1. /* c语言实现 */
  2. typedef int ElementType; // 默认元素可以用非负整数表示
  3. typedef int SetName; //默认用根结点的下标作为集合名称
  4. typedef ElementType SetType[MaxSize];
  5. SetName Find(SetType S, ElementType X)
  6. {
  7. // 默认集合元素全部初始化为-1
  8. for (; S[X] >= 0; X = S[X]);
  9. return X;
  10. }
  11. void Union(SetType S, SetName Root1, SetName Root2)
  12. {
  13. // 这里默认Root1和Root2是不同集合的根节点
  14. S[Root2] = Root1;
  15. }

二、题意理解

根据输入样例,以此来判断计算机之间有多少个组成,如下图所示

上图动态变化如下图所示:

下图为五台计算机之间形成全连接状态,因此看成一个整体:

三、程序框架搭建

  1. /* c语言实现 */
  2. int main()
  3. {
  4. 初始化集合;
  5. do {
  6. 读入一条指令;
  7. 处理指令;
  8. } while (没结束);
  9. return 0;
  10. }
  11. int main()
  12. {
  13. SetType S;
  14. int n;
  15. char in;
  16. scanf("%d\n", &n);
  17. Initialization(S, n);
  18. do {
  19. scanf("%c", &in);
  20. switch (in) {
  21. case 'I': Input_connection(S); break; // Union(Find)
  22. case 'C': Check_connection(S); break; // Find
  23. case 'S': Check_network(S, n); break; // 数集合的根,判断计算机网络的组成个数
  24. }
  25. } while (in != 'S');
  26. return 0;
  27. }

3.1 Input_connection

  1. /* c语言实现 */
  2. void Input_connection(SetType S)
  3. {
  4. ElementType u, v;
  5. SetName Root1, Root2;
  6. scanf("%d %d\n", &u, &v);
  7. Root1 = Find(S, u-1);
  8. Root2 = Find(S, v-1);
  9. if (Root1 != Root2)
  10. Union(S, Root1, Root2);
  11. }

3.2 Check_connection

  1. /* c语言实现 */
  2. void Check_connection(SetType S)
  3. {
  4. ElementType u, v;
  5. scnaf("%d %d\n", &u, &v);
  6. Root1 = Find(S, u-1);
  7. Root2 = Find(S, v-1);
  8. if (Root1 == Root2)
  9. printf("yes\n");
  10. else printf("no\n");
  11. }

3.3 Check_network

  1. /* c语言实现 */
  2. void Check_network(SetType S, int n)
  3. {
  4. int i, counter = 0;
  5. for (i = 0; i < n; i++){
  6. if (S[i] < 0) counter++;
  7. }
  8. if (counter == 1)
  9. printf("The network is connected.\n");
  10. else
  11. printf("There are %d components.\n", counter);
  12. }

四、pta测试

  1. /* c语言实现 */
  2. typedef int ElementType; // 默认元素可以用非负整数表示
  3. typedef int SetName; //默认用根结点的下标作为集合名称
  4. typedef ElementType SetType[MaxSize];
  5. SetName Find(SetType S, ElementType X)
  6. {
  7. // 默认集合元素全部初始化为-1
  8. for (; S[X] >= 0; X = S[X]);
  9. return X;
  10. }
  11. void Union(SetType S, SetName Root1, SetName Root2)
  12. {
  13. // 这里默认Root1和Root2是不同集合的根节点
  14. S[Root2] = Root1;
  15. }

对于上述的代码,如果我们放入pta中测试,会发现测试点6运行超时,如下图所示:

因此,我们会考虑是不是因为出现了某种情况,导致Root2为根结点的树过大了,因此我们修改代码为:

  1. /* c语言实现 */
  2. typedef int ElementType; // 默认元素可以用非负整数表示
  3. typedef int SetName; //默认用根结点的下标作为集合名称
  4. typedef ElementType SetType[MaxSize];
  5. SetName Find(SetType S, ElementType X)
  6. {
  7. // 默认集合元素全部初始化为-1
  8. for (; S[X] >= 0; X = S[X]);
  9. return X;
  10. }
  11. void Union(SetType S, SetName Root1, SetName Root2)
  12. {
  13. // 这里默认Root1和Root2是不同集合的根节点
  14. // S[Root2] = Root1;
  15. S[Root1] = Root2;
  16. }

发现更换代码后,测试点5却运行超时了,为了解决上述问题,我们可以使用下面将要讲到了按秩归并的思想修改代码。

五、按秩归并

为什么需要按秩归并呢?因为我们使用pta测试程序,发现代码总是超时,因此我们可以考虑是否出现这种情况——我们再不断地往一颗树上累加子树,如下图所示:

  1. /* c语言实现 */
  2. Union(Find(2), Find(1));
  3. Union(Find(3), Find(1));
  4. ……;
  5. Union(Find(n), Find(1));

从上图可以看出,此过程的时间复杂度为:\(T(n) = O(n^2)\)

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

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

5.1 方法一:树高替代

为了解决上述问题,我们可以把根结点从-1替代为-树高,代码如下:

  1. /* c语言实现 */
  2. if ( Root2高度 > Root1高度 )
  3. S[Root1] = Root2;
  4. else {
  5. if ( 两者等高 ) 树高++;
  6. S[Root2] = Root1;
  7. }
  8. if ( S[Root2] < S[Root1] )
  9. S[Root1] = Root2;
  10. else {
  11. if ( S[Root1]==S[Root2] ) S[Root1]--;
  12. S[Root2] = Root1;
  13. }

5.2 方法二:规模替代

为了解决上述问题,我们也可以把根结点从**-1替代为-元素个数(把小树贴到大树上),代码如下:

  1. /* c语言实现 */
  2. void Union( SetType S, SetName Root1, SetName Root2 )
  3. {
  4. if ( S[Root2]<S[Root1] ){
  5. S[Root2] += S[Root1];
  6. S[Root1] = Root2;
  7. } else {
  8. S[Root1] += S[Root2];
  9. S[Root2] = Root1;
  10. }
  11. }

六、路径压缩

对于上述代码超时的问题,我们也可以使用路径压缩的方法优化代,即压缩给定元素到集合根元素路径中的所有元素,详细情况如下图所示:

上图代码可表示为:

  1. /* c语言实现 */
  2. SetName Find(SetType S, ElementType X)
  3. {
  4. // 找到集合的根
  5. if (S[X] < 0)
  6. return X;
  7. else
  8. return S[X] = Find(S, S[X]);
  9. }

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

  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. 记录一次Jquery中 this 关键字使用出现的问题

    今天在用Jquery改造之前的JS代码过程中,遇到了一个让我懵逼了三小时的问题. 问题的关键在 this 的使用.在这里与大家分享一下.并且分享一下我做表单提交的检查代码 错误代码如下: $(&quo ...

  2. PicGo+GitHub:你的最佳免费图床选择!

    # PicGo介绍 这是一款图片上传的工具,目前支持SM.MS图床,微博图床,七牛图床,腾讯云COS,阿里云OSS,Imgur,又拍云,GitHub等图床,未来将支持更多图床. 所以解决问题的思路就是 ...

  3. egret之消除游戏开发

    1.地图 (1)地图形状不同,尺寸不变 (2)背景图变化 2.步数 (1)不同关卡步数不同 (2)步数为01,游戏失败 3.道具 4.消除 (1)>=3可消除 (2)不可消除时,自动打乱 5.数 ...

  4. JavaScript中几种常见的兼容问题及解决方案

    在js中好用的东西一般都存在兼容问题,以下,我整理了一些常用的兼容处理方法,自己用的时候可以把他们放在一个JS文件中,需要用到时候直接引入,会比较方便. 一.获取非行内样式 function getS ...

  5. centos6在安装wdcp以后,导入MySQLdb报错问题

    为了方便linux的使用,会先安装好wdcp对服务器进行管理.在装好wdcp会对一些nginx,mysql等自动安装,但是mysql的安装目录会在/www/wdlinux这个目录下,跟一般的mysql ...

  6. Nginx总结(五)如何配置nginx和tomcat实现反向代理

    前面讲了如何配置Nginx虚拟主机,大家可以去这里看看nginx系列文章:https://www.cnblogs.com/zhangweizhong/category/1529997.html 今天要 ...

  7. spring-cloud-kubernetes与SpringCloud Gateway

    本文是<spring-cloud-kubernetes实战系列>的第五篇,主要内容是在kubernetes上部署一个SpringCloud Gateway应用,该应用使用了spring-c ...

  8. ubuntu安装elasticsearch及head插件

    1.安装elasticsearch,参考http://www.cnblogs.com/hanyinglong/p/5409003.html就可以了 简单描述下: mkdir -p /usr/local ...

  9. Python实现 下载IJCAI会议所有论文

    import requests import threading def get_file_content(num): savepath = '%04d.pdf' % (num) suburl = ' ...

  10. 牛客网 Wannafly挑战赛 A 找一找 思考题

    链接:https://www.nowcoder.com/acm/contest/71/A来源:牛客网 题目描述 给定n个正整数,请找出其中有多少个数x满足:在这n个数中存在数y=kx,其中k为大于1的 ...