树的父指针表示与Union/Find算法实现

合并两个节点所在的子树

#include <iostream>
using namespace std;

//类ParTreeNode描述了树的结点定义
template<class T>
class ParTreeNode                           //树结点定义
{
private:
    T                value;                 //结点的值
    ParTreeNode<T>* parent;                 //父结点指针
    int        nCount;                      //以此结点为根的子树的总结点个数
public:
    ParTreeNode();                          //构造函数
    virtual ~ParTreeNode() {};              //析构函数
    T    getValue();                        //返回结点的值
    void  setValue(const T& val);           //设置结点的值
    ParTreeNode<T>*  getParent();           //返回父结点指针
    void  setParent(ParTreeNode<T>* par);   //设置父结点指针
    int   getCount();                       //返回结点数目
    void  setCount(const int count);        //设置结点数目
};

//ParTreeNode抽象数据类型成员函数的实现
template<class T>
ParTreeNode<T>::ParTreeNode()               //构造函数
{
    parent = NULL;
    nCount = 1;
}
template<class T>
T ParTreeNode<T>::getValue()                //返回结点的值
{
    return value;
}
template<class T>
void ParTreeNode<T>::setValue(const T& val) //设置结点的值
{
    value = val;
}
template<class T>
ParTreeNode<T>* ParTreeNode<T>::getParent() //返回父结点指针
{
    return parent;
}
template<class T>
void ParTreeNode<T>::setParent(ParTreeNode<T>* par) //设置父结点指针
{
    parent = par;
}
template<class T>
int ParTreeNode<T>::getCount()                      //返回结点数目
{
    return nCount;
}
template<class T>
void ParTreeNode<T>::setCount(const int count)      //设置结点数目
{
    nCount = count;
}


//类ParTree描述了树的定义
template<class T>
class ParTree                                       //树定义
{
public:
    ParTreeNode<T>* array;                          //存储树结点的数组
    int    Size;                                    //数组大小
    ParTree(const int size);                        //构造函数
    virtual ~ParTree();                             //析构函数
    ParTreeNode<T> *Find(ParTreeNode<T>* node)const;//查找node结点的根结点
    ParTreeNode<T> *FindPC(ParTreeNode<T> *node) const; // 带压缩

    void Union(int i,int j);                    //把下标为i,j的结点合并成一棵子树
    void UnionPC(int i, int j);                 //带压缩
    bool Different(int i,int j);                //判定下标为i,j的结点是否在一棵树中

    int getSize()                               // 输出树结点的个数
    {
        return Size;
    }
};

//树的成员函数的实现
template <class T>
ParTree<T>::ParTree(const int size)             //构造函数
{
    Size = size;
    array = new ParTreeNode<T>[size];
}

template <class T>
ParTree<T>::~ParTree()                           //构造函数
{
    delete []array;
}

// 函数功能:找到目标结点的根结点
template <class T>
ParTreeNode<T>*    ParTree<T>::Find(ParTreeNode<T>* node) const
{
    ParTreeNode<T>* pointer = node;
    while(pointer->getParent() != NULL)
        pointer = pointer->getParent();
    return pointer;
}

//函数功能:带路径压缩的Find算法
template <class T>
ParTreeNode<T> *ParTree<T>::FindPC(ParTreeNode<T> *node) const
{
    if (node->getParent() == NULL)
        return node;

    node->setParent(FindPC(node->getParent()));
    return node->getParent();
}

//函数功能:判定下标为i,j的结点是否在一棵树中
template<class T>
bool ParTree<T>::Different(int i,int j)
{
    ParTreeNode<T>* pointeri = Find(&array[i]);        //找到结点i的根
    ParTreeNode<T>* pointerj = Find(&array[j]);        //找到结点j的根
    return pointeri != pointerj;
}

//把下标为i,j的结点合并成一棵子树
template<class T>
void ParTree<T>::Union(int i,int j)
{
    ParTreeNode<T>* pointeri = Find(&array[i]);        //找到结点i的根
    ParTreeNode<T>* pointerj = Find(&array[j]);        //找到结点j的根
    if(pointeri != pointerj)
    {
        if(pointeri->getCount()>=pointerj->getCount())
        {
            pointerj->setParent(pointeri);
            pointeri->setCount(pointeri->getCount()+pointerj->getCount());
        }
        else
        {
            pointeri->setParent(pointerj);
            pointerj->setCount(pointeri->getCount()+pointerj->getCount());
        }
    }
}

// 函数功能:归并两个集合, 带压缩
template <class T>
void ParTree<T>::UnionPC(int i, int j)
{
    ParTreeNode<T> *pointeri = FindPC(&array[i]);
    ParTreeNode<T> *pointerj = FindPC(&array[j]);

    if (pointeri != pointerj)
    {
        if (pointeri->getCount() >= pointerj->getCount())
        {
            pointerj->setParent(pointeri);
            pointeri->setCount(pointeri->getCount() + pointerj->getCount());
        }
        else
        {
            pointeri->setParent(pointerj);
            pointerj->setCount(pointeri->getCount() + pointerj->getCount());
        }
    }
}

const int N = 10;                              // 树结点个数
char strInfo[N] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'};  //结点信息数组

// 函数功能:根据字符信息获得数字在数组中的位置下标
int GetNum(char ch)  {
    for (int i = 0; i < N; i ++)
        if (ch == strInfo[i])
            return i;
    return -1;
}

// 函数功能:显示数据在父指针表示法中的父结点下标
void Display(ParTree<char> &aParTree)  {
    for (int i = 0; i < N; i ++)  {
        if (aParTree.array[i].getParent() == NULL)            //如果是没有父结点就用*表示
        cout << "*" << " ";
        else  {
            char ch = aParTree.array[i].getParent()->getValue(); //如果有父结点就打印数组中的父结点的下标
            cout << GetNum(ch) << " ";
        }
    }
    cout << endl;
}

#define PATHCOMPRESSION 0 // 0-不带压缩
// 1-带压缩

int main()
{
    ParTree<char> aParTree(N);
    cout << "* means that the node has no parents!\n" ;

    int i;
    for (i = 0; i < N; i++)
        cout << i << " ";
    cout << endl;

    for (i = 0; i < N; i++)
    {
        aParTree.array[i].setValue(strInfo[i]);
        cout << strInfo[i] << " ";
    }
    cout << endl;

    cout << "Union: (A,B),(C,D),(E,F),(G,H),(I,J)\n" ;
    aParTree.Union(GetNum('A'), GetNum('B'));
    aParTree.Union(GetNum('C'), GetNum('D'));
    aParTree.Union(GetNum('E'), GetNum('F'));
    aParTree.Union(GetNum('G'), GetNum('H'));
    aParTree.Union(GetNum('I'), GetNum('J'));
    Display(aParTree);                             //显示数据在父指针表示法中的父结点下标
    // 结果:* 0 * 2 * 4 * 6 * 8

    cout << "\nUnion: (A,D),(I,H)\n";
    aParTree.Union(GetNum('A'), GetNum('D'));
    aParTree.Union(GetNum('I'), GetNum('H'));
    Display(aParTree);                                //显示数据在父指针表示法中的父结点下标
    // 结果:* 0 0 2 * 4 8 6 * 8

#if !PATHCOMPRESSION
    // 0.不带压缩
    cout << "\nUnion: (F,J)\n" ;
    aParTree.Union(GetNum('F'), GetNum('J'));
    Display(aParTree);                                //显示数据在父指针表示法中的父结点下标
    // 结果:* 0 0 2 8 4 8 6 * 8

    cout << "Union: (D,J)\n";
    aParTree.Union(GetNum('D'), GetNum('J'));
    Display(aParTree);                                //显示数据在父指针表示法中的父结点下标
    // 结果:8 0 0 2 8 4 8 6 * 8
#else
    // 1.带压缩
    cout << "\nUnion: (F,J)\n";
    aParTree.UnionPC(GetNum('F'), GetNum('J'));
    Display(aParTree);                                //显示数据在父指针表示法中的父结点下标
    cout << "\nUnion: (D,J)\n";
    aParTree.UnionPC(GetNum('D'), GetNum('J'));
    Display(aParTree);                                //显示数据在父指针表示法中的父结点下标
#endif

    if (aParTree.Different(GetNum('D'), GetNum('E')))
        cout << "D and E are in different sets!!!" << endl;
    else
        cout << "D and E are in a common set!!!" << endl;
    cout << endl;

    return 0;
}


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值