小米:朋友圈,並查集


題目:假如已知有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

大牛寫的很詳細,附有代碼!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章