題目:假如已知有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
大牛寫的很詳細,附有代碼!