题目:假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写出程序求出这n个人里一共有多少朋友圈。
例如:n=5,m=3,r={{1,2},{2,3},{4,5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友。则1,2,3属于一个朋友圈,4,5属于另一个朋友圈,结果为两个朋友圈。
知识点:并查集。
代码:
#include<iostream>
using namespace std;
class friends{
public:
friends(int n);//构造函数
friends(const friends& f);//复制构造函数
friends& operator=(const friends& f);//赋值构造函数
~friends();//析构函数
int find(int x);
void merge(int x, int y);
int friendsCircles(int n, int m, int r[][2]);
private:
int _n;
int* _set;
};
friends::friends(int n):_n(n), _set(new int[n+1]){//构造函数,n+1是因为数组的第0个元素没有使用,所以n个元素需要申请n+1个空间
cout << "调用构造函数开始!" << endl;
int i;
for(i = 1; i <= n; ++i)
_set[i] = i;
cout << "调用构造函数结束!" << endl;
}
friends::friends(const friends& f){//深复制
cout << "调用复制构造函数开始!" << endl;
_n = f._n;
_set = new int[_n+1];
memcpy(_set, f._set, (f._n+1) * sizeof(int));
cout << "调用复制构造函数结束!" << endl;
}
friends& friends::operator=(const friends& f){
if(&f != this){
friends tempFriends(f);
int *pTemp = tempFriends._set;
tempFriends._set = _set;
_set = pTemp;
}
return *this;
}
friends::~friends(){//析构函数
cout << "调用析构函数开始!" << endl;
delete[] _set;
cout << "调用析构函数结束!" << endl;
}
int friends::find(int x){
cout << "调用find函数开始!" << endl;
int i, j, r;
r = x;
while(r != _set[r])//找到代表
r = _set[r];
i = x;
while(i != r){//压缩路径
j = _set[i];
_set[i] = r;
i = j;
}
cout << "调用find函数结束!" << endl;
return r;
}
void friends::merge(int x, int y){
cout << "调用merge函数开始!" << endl;
int parentX = find(x);
int parentY = find(y);
if(parentX < parentY)//大 -> 小
_set[parentY] = parentX;
else
_set[parentX] = parentY;
cout << "调用merge函数结束!" << endl;
}
int friends::friendsCircles(int n, int m, int r[][2]){
cout << "调用friendsCircles函数开始!" << endl;
int i;
int count = 0;
for(i = 0; i < m; ++i)
merge(r[i][0], r[i][1]);
for(i = 1; i <= n; ++i){
if(_set[i] == i)
++count;
}
cout << "调用friendsCircles函数结束!" << endl;
return count;
}
void test1(){//测试在堆上实例化对象
int r[][2] = {{1,2},{2,3},{4,5},{5,9},{6,2},{7,8}};
int n = 9;
int m = 6;
friends *f = new friends(n);//f在堆上
int count = f->friendsCircles(n, m, r);
cout << "朋友圈的个数:" << count << endl;
delete f;//因为f在堆上,所以程序结束时,不会自动调用friends的析构函数,只有用delete时,才调用析构函数
}
void test2(){//测试在栈上实例化对象
int r[][2] = {{1,2},{2,3},{4,5},{5,9},{6,2},{7,8}};
int n = 9;
int m = 6;
friends f(n);//f在栈上
int count = f.friendsCircles(n, m, r);
cout << "朋友圈的个数:" << count << endl;//因为f在栈上,所以程序结束时,会自动调用friends的析构函数。
}
void test3(){//测试复制函数
int r[][2] = {{1,2},{2,3},{4,5},{5,9},{6,2},{7,8}};
int n = 9;
int m = 6;
friends f(n);//f在栈上
friends ff(f);
int count = ff.friendsCircles(n, m, r);
cout << "朋友圈的个数:" << count << endl;
}
void test4(){//测试赋值函数
int r[][2] = {{1,2},{2,3},{4,5},{5,9},{6,2},{7,8}};
int n = 9;
int m = 6;
friends f(n);//f在栈上
friends ff(n+2);
ff = f;
int count = ff.friendsCircles(n, m, r);
cout << "朋友圈的个数:" << count << endl;
}
int main(){
test1();
//test2();
//test3();
//test4();
return 0;
}
这里我写了一个比较完全的类,由于类包含了指针成员,所以需要自己写 析构函数,这又导致需要自己写复制构造函数和赋值构造函数(三法则)。
下一篇文章我讲总结一下我在写这些代码时遇到的一些 尴尬问题!
关于带指针成员的类的 书写方法,建议参考: http://www.cnblogs.com/lucy-lizhi/p/6551308.html
大牛写的很详细,附有代码!