QingfengLee
12/7/2015 - 1:55 AM

并查集算法,DisjointSet,具体原理请参看http://blog.csdn.net/qianchenglenger/article/details/47378501

并查集算法,DisjointSet,具体原理请参看http://blog.csdn.net/qianchenglenger/article/details/47378501

/**
 * @brief 并查集算法,Quick-Find
 */
class DisjointSet
{
public:
    /**
     * 构造函数,并设置元素个数
     * @param[in] size 初始化的并查集,设置的元素个数
     */
    DisjointSet(int size)
    {
        id = new int[size];
        for (int i = 0; i < size; ++i)
        {
            makeSet(i);
        }
        num = size;
    }

    /**
     * @brief 析构函数
     */
    ~DisjointSet()
    {
        delete[] id;
    }

    /**
     * @brief 将包含p和q的两个动态集合(表示为Sp和Sq)合并成一个新的集合
     * @param[in] p 需要进行合并的其中一个集合元素
     * @param[in] q 需要进行合并的其中一个集合元素
     */
    inline void unionElem(int p, int q)
    {
        int pID = find(p);
        int qID = find(q);
        if (pID == qID) return;
        //遍历一次,该表所有的组号,并该表其中一组的组号,使两组合并
        for (int i = 0; i < num; ++i)
        {
            if (id[i] == pID)
                id[i] = qID;
        }
        --num;
    }

    /**
     * @brief 找到元素p的代表
     * @param[in] p需要获取代表的元素
     * @return 元素p的代表
     */
    inline int find(int p)
    {
        return id[p];
    }

    /**
     * @brief 获取集合的个数
     * @return 当前集合的个数
     */
    inline int getSetNum()
    {
        return num;
    }

private:
    /**
     * @brief 建立一个新的集合,它的唯一成员(因而为代表)是p
     * @param p 创建集合的唯一成员元素
     */
    inline void makeSet(int p)
    {
        id[p] = p;
    }

private:
    int * id;   //并查集的元素
    int num;    //并查集的组数
};
/**
 * @brief 并查集算法,Union by rank With Path Compression
 */
class DisjointSet
{
public:
    /**
     * 构造函数,并设置元素个数
     * @param[in] size 初始化的并查集,设置的元素个数
     */
    DisjointSet(int size)
    {
        id = new int[size];
        weight = new int[size];
        for (int i = 0; i < size; ++i)
        {
            makeSet(i);
        }
        num = size;
    }

    /**
     * @brief 析构函数
     */
    ~DisjointSet()
    {
        delete[] id;
        delete[] weight;
    }

    /**
     * @brief 将包含p和q的两个动态集合(表示为Sp和Sq)合并成一个新的集合
     * @param[in] p 需要进行合并的其中一个集合元素
     * @param[in] q 需要进行合并的其中一个集合元素
     */
    inline void unionElem(int p, int q)
    {
        // Give p and q the same root.  
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot)
            return;
        //将高度较低的树做为高度较低的树的子树
        if (weight[pRoot] < weight[qRoot])
        {
            id[pRoot] = qRoot;
        }
        else
        {
            id[qRoot] = pRoot;
            if (weight[pRoot] == weight[qRoot])
                ++weight[pRoot];
        }
        --num;
    }

    /**
     * @brief 找到元素p的代表
     * @param[in] p需要获取代表的元素
     * @return 元素p的代表
     */
    inline int find(int p)
    {
        if (p != id[p])
            id[p] = find(id[p]);
        return id[p];
    }

    /**
     * @brief 获取集合的个数
     * @return 当前集合的个数
     */
    inline int getSetNum()
    {
        return num;
    }

private:
    /**
     * @brief 建立一个新的集合,它的唯一成员(因而为代表)是p
     * @param p 创建集合的唯一成员元素
     */
    inline void makeSet(int p)
    {
        id[p] = p;
        weight[p] = 1;  //每个节点初始化权重都是1(都只含有一层)
    }

private:
    int * id;       //并查集的元素
    int * weight;   //对应一棵树的高度,并将其作为权重,即rank
    int num;        //并查集的组数
};