老规矩,先把何老师的PPT安排一下,后面直接上代码
一、集合的表示及查找
二、集合的简化表示
测试:
三、程序框架的搭建
四、按秩归并(对Union函数的改进)
姥姥推荐使用比规模 !!!
五、路径压缩(对Find()函数的改进)
尾递归在系统中可能会自动转化为优化后的循环代码,所以可以放心使用。
六、疑惑点解答:
1.在Find()函数中的第二步递归操作等价于:arr[Xn]=arr[Xn-1]=...=arr[X0]=X0,相当于是把根节点的编号作为前面递归的所有节点的父节点(通过赋值操作来让自己成为其他节点的父节点)。
2.对于根节点arr[Xi]=-规模,而其他的一般节点arr[Xj]里面保存的是Xj父节点的下标Xi。
3.Q:Union()函数到底是如何把儿子节点挂在父节点上的?
A:如上所述,首先比较两个父节点谁的规模更大,将较小的规模加到较大规模上,其次将root2的父节点即arr[root2]用root1下标来覆盖,这样身为父亲的root2里面的元素arr[root2]就变成了父节点的位置(是一个正数),他自己自然不能再做父亲了(因为所有父节点的数据域均保存的是-孩子的规模),但是依旧瘦死的骆驼比马大,因为他的儿子节点的数据域依旧记录这他的位置,只不过孩子要想找到真正的祖先还要继续向父节点的再上一层去寻找。
七、以下是代码详解(保姆级教程):
#include<iostream>
using namespace std;
const int MaxSize = 100;
typedef int ElementType;
void Init(ElementType arr[], int N) {
for (int i = 0;i < N;i++)
arr[i] = -1;//规模设置为1,父节点就是自身
}
//查找根节点,返回值是根节点的下标(路径压缩)
int Find(ElementType arr[], int num) {
if (arr[num] < 0)
return num; //根节点存放的数据是:-规模
else // 1. 找到根 2. 把根变成 x 的父结点 3.再返回根
return arr[num] = Find(arr, arr[num]);//最内层返回的是根节点的下标,然后依次传给其他节点的数据域,作为其他节点的父节点
}
//合并根节点:把编号为num1和num2的计算机合并(num1,num2已经是根节点了)
void Union(ElementType arr[], int root1, int root2) {
//默认已经是根节点了
if (arr[root1] < arr[root2]) {
arr[root1] += arr[root2];
arr[root2] = root1; //将root2的父节点即arr[root2]设置为root1,arr[root2]是指root2的根节点
}
else {
arr[root2] = arr[root1];
arr[root1] = root2;
}
}
//连接两台计算机
void Input_connection(ElementType arr[]) {
int num1, num2;//num1,num2为计算机的实际编号
cout << "请输入需要连接的两台计算机的编号:";
cin >> num1 >> num2;
int root1 = Find(arr, num1);
int root2 = Find(arr, num2);
if (root1 != root2)
Union(arr, root1, root2);
}
//检查两台计算机之间是否已经相连
void check_connection(ElementType arr[]) {
int num1, num2;
cout << "请输入需要查询是否连接的两台计算机的编号:";
cin >> num1 >> num2;
int root1 = Find(arr, num1);
int root2 = Find(arr, num2);
if (root1 != root2) cout << "未连接" << endl;
else cout << "已连接" << endl;
}
//检查整个计算机网络是否相连
void check_internet(ElementType arr[],int N) {
int cnt = 0;
for (int i = 0;i < N;i++)
if (arr[i] < 0)
cnt++;
if (cnt == 1) cout << "The network is connected." << endl;
else cout << "The network is " << cnt << " part connected." << endl;
}
int main() {
int N;
char in;
cout << "请输入机房的计算机总数:";
cin >> N;
cout << "输入操作指南(I:将两台计算机联通 C:检查两个网络之间是否连通 S:检查整个网络是否连通)" << endl;
ElementType arr[MaxSize];
Init(arr, N);
do {
cout << "请输入操作:";
cin >> in;
switch (in)
{
case'i':Input_connection(arr);break;
case'c':check_connection(arr);break;
case's':check_internet(arr, N);break;
default:
break;
}
} while (in != 's');
system("pause");
return 0;
}