0x01 实验目的
掌握在线等价类的使用,要求使用模拟指针实现。
0x02 实验内容
- 使用模拟指针实现本实验。
- 输入一个1-9的正整数n,代表要创建n个元素,例如输入5,则代表创建一个1,2,3,4,5组成的元素表。
- 再输入一个大于0正整数r,代表后面要输入r个等价关系。
- 分行输入r个等价关系,格式如(1,2)。
- 分行输出所有等价类,一个等价类的元素由小到大依次输出。例如等价类(1,3,5,2,4),输出时排序输出(1,2,3,4,5)。
- 如果输出不是由小到大顺序输出,解决办法很多,可以创建一个n*n的数组,一行存放一个等价类,将所有等价类放入数组,对数组每一行元素进行排序,输出数组所有元素。
0x03 实验过程
路径压缩
采用递归的形式,将链状的结构,变成树状,每一个节点的指针域都存的是自己的祖先节点,而不仅是父节点。
int Find(int i) {if(i == node[i].next) return i;else {node[i].next = Find(node[i].next);return node[i].next;}
}
合并判断&合并顺序
- 在合并两个类时,要判断它们的祖宗节点是否是同一个,如果是就不再合并,不是才合并。
- order is important:必须确保两个数合并,必须由小的数指向大的数,因为在后面遍历时,如果是大的指向小的,而小的又没指向其他节点时,因为从小到大遍历的局限性,会直接将小的数当成单个类直接输出。
void unite(int m,int n) {//order is importantif(m > n) swap(m,n);int i = Find(m);int j = Find(n);if(i != j) node[i].next = j;
}
输出判断顺序
for(int i = 1; i <= num; i++) {//order is important?if(Find(i) != i && arr[i] == false) {//cout<<i;int sum = 0;for(int j = 1; j <= num; j++) {//first 1 is specialif(arr[j] == true) continue;//first is easyif(sum == 0) {cout<<"(";cout<<j;arr[j] = true;}if(Find(j) == Find(i) && sum != 0) {cout<<","<<j;arr[j] = true;}sum++;}if(sum != 0) {cout<<")"<<endl;}} else {if(Find(i) == i && arr[i] == false) {cout<<"("<<i<<")"<<endl;arr[i] = true;}}}
括号输出问题
先输出(
然后逗号跟在数字前输出,比逗号跟在数字后输出好:把第一个当成特殊情况,比把最后一个当成特殊情况要好。(最后一个在不知数量的情况下,不好判断)
if(sum == 0) {cout<<"(";cout<<j;arr[j] = true;}
if(Find(j) == Find(i) && sum != 0) {cout<<","<<j;arr[j] = true;
}
0x04 完整源码
参考视频:图论-并查集(Bilibli)
#include <bits/stdc++.h>
using namespace std;//定义节点
struct Node {int value,next;
};
Node *node;
int num;//记录是否已经被使用过
bool arr[100];//初始化,每个元素都指向自己,且值为0
void init(int sum) {num = sum;node = new Node [num + 1];for(int i = 0; i <= num; i++) {node[i].next = i;node[i].value = 0;}
}//查询祖宗节点操作
int Find(int i) {if(i == node[i].next) return i;else {node[i].next = Find(node[i].next);return node[i].next;}
}//合并节点操作
void unite(int m,int n) {//order is importantif(m > n) swap(m,n);int i = Find(m);int j = Find(n);if(i != j) node[i].next = j;
}int main() {cout<<"Input"<<endl;cin>>num;//初始化num个节点init(num);int p;cin>>p;//p个等价关系for(int i = 0; i < p; i++) {string s = "";cin>>s;unite(int(s.at(1)) - 48,int(s.at(3)) - 48);}cout<<"Output"<<endl;for(int i = 1; i <= num; i++) {//order is importantif(Find(i) != i && arr[i] == false) {//cout<<i;int sum = 0;for(int j = 1; j <= num; j++) {//first 1 is specialif(arr[j] == true) continue;//first is easyif(sum == 0) {cout<<"(";cout<<j;arr[j] = true;}if(Find(j) == Find(i) && sum != 0) {cout<<","<<j;arr[j] = true;}sum++;}if(sum != 0) {cout<<")"<<endl;}} else {if(Find(i) == i && arr[i] == false) {cout<<"("<<i<<")"<<endl;arr[i] = true;}}}cout<<"End"<<endl;return 0;
}