森林的双亲孩子表示法的设计与实现

829 阅读3分钟

问题:仿照树的双亲孩子表示法,设计森林的双亲孩子存储结构。要求实现森林的先根、中根、后根遍历,能求森林的规模(森林中树的数目)、森林的高度(森林中树的最大高度)、森林的叶子数(森林中所有树的叶子之和)。

这是笔者在学习数据结构时遇到的一个题目。

以先根遍历为例。先根遍历需要先访问第一棵树的根结点,再先根遍历第一棵树根结点的子树组成的森林,再先根遍历除第一棵树之外的其他树组成的森林。那么最重要的是就是用什么来表示一个森林呢?对于一棵树我们可以通过它的根结点来表示,但是森林是由若干个树组成的,他是没有根结点的。所以我们就可以创造一个虚拟的根结点,来代表这整个森林。我们用这个虚拟根结点的第一个孩子来表示第一棵树的子树,再设置一个虚拟结点2,并且连接上除第一棵树之外的树,以表示这个森林。那么遍历的问题就迎刃而解。

例子如下。

代码如下:

//ParentChildForest.h

#ifndef PARENTCHILDFOREST_H
#define PARENTCHILDFOREST_H
#include "Node.h"
#include <iostream>
using namespace std;

template<class ElemType>
class ParentChildForest
{
public:
    ParentChild<ElemType> a[50];        //存储空间
    ParentChild<ElemType> *root;
    int num;                    //总结点个数
public:
    ParentChildForest(ElemType item[],int parents[],int Num=0);        //有参数的构造函数
    void PreOrder(ParentChild<ElemType> r);            //先根遍历r为的子树森林
    void MidOrder(ParentChild<ElemType> r);            //中根遍历r为的子树森林
    void PostOrder(ParentChild<ElemType> r);        //后根遍历r为的子树森林
    int TreeNum();                //求森林中树的数目
    int Height();                //求森林的高度
    int Leaf();                    //叶子数
    void Show();
};

template<class ElemType>
ParentChildForest<ElemType>::ParentChildForest(ElemType item[],int parents[],int Num)
{
    int i;
    for(i=0;item[i]!=NULL;i++){            //全部存放到结点数组内
        a[i+1].data = item[i];
        a[i+1].parent = parents[i];
        a[i+1].firstChild = NULL;
    }
    a[0].parent=-1;
    num=Num;
    a[0].data=a[2].data;
    *root=a[0];
    for(i=1;i<=num;i++){            //构造各个结点的孩子的单链表
        Child<ElemType> *p,*q;
        q = new Child<ElemType>(i,NULL);
        if(a[a[i].parent].firstChild==NULL){
            a[a[i].parent].firstChild=q;
        }
        else{
            for(p=a[a[i].parent].firstChild;p->next!=NULL;p=p->next){}
            p->next=q;
        }
    }
    root->firstChild=a[0].firstChild;
}

template<class ElemType>
void ParentChildForest<ElemType>::PreOrder(ParentChild<ElemType> r)
{    //先根遍历
    if(r.firstChild!=NULL){        //若森林不为空
        cout<<a[r.firstChild->data].data<<"  ";        //访问第一棵树的根结点
        PreOrder(a[r.firstChild->data]);    //先根遍历第一棵树的根结点的子树森林
        if(r.firstChild->next!=NULL){
            ParentChild<ElemType> temp;
            temp.firstChild = r.firstChild->next;
            PreOrder(temp);                    //先根遍历其他树组成的森林
        }
    }
}

template<class ElemType>
void ParentChildForest<ElemType>::MidOrder(ParentChild<ElemType> r)
{    //中根遍历
    if(r.firstChild!=NULL){        //若森林不为空
        MidOrder(a[r.firstChild->data]);    //中根遍历第一棵树的根结点的子树森林
        cout<<a[r.firstChild->data].data<<"  ";        //访问第一棵树的根结点
        if(r.firstChild->next!=NULL){
            ParentChild<ElemType> temp;
            temp.firstChild = r.firstChild->next;
            MidOrder(temp);                    //中根遍历其他树组成的森林
        }
    }
}

template<class ElemType>
void ParentChildForest<ElemType>::PostOrder(ParentChild<ElemType> r)
{    //后根遍历
    if(r.firstChild!=NULL){        //若森林不为空
        PostOrder(a[r.firstChild->data]);    //后根遍历第一棵树的根结点的子树森林
        if(r.firstChild->next!=NULL){
            ParentChild<ElemType> temp;
            temp.firstChild = r.firstChild->next;
            PostOrder(temp);                    //后根遍历其他树组成的森林
        }
        cout<<a[r.firstChild->data].data<<"  ";        //访问第一棵树的根结点
    }
}

template<class ElemType>
int ParentChildForest<ElemType>::TreeNum()
{    //返回森林中树的数目

    int treenum=0;
    Child<ElemType> *p;
    p=a[0].firstChild;
    for(;p!=NULL;p=p->next){
        treenum++;
    }
    return treenum;

}

template<class ElemType>
int ParentChildForest<ElemType>::Height()
{    //求森林的高度
    if(a[0].firstChild!=NULL){
        int temp=0,height=0;
        Child<ElemType> *p;
        p=a[0].firstChild;
        for(;p->next!=NULL;p=p->next){
            temp=0;
            int i=p->next->data-1;
            while(a[i].parent>=0){
                i=a[i].parent;
                temp++;
            }
            height=(temp>height)?temp:height;
        }
        temp=0;
        int i=num;
        while(a[i].parent>=0){
            i=a[i].parent;
            temp++;
        }
        height=(temp>height)?temp:height;
        return height;
    }
    else{
        return 0;
    }
}

template<class ElemType>
int ParentChildForest<ElemType>::Leaf()
{
    int leaf=0;
    for(int i=0;i<=num;i++){
        if(a[i].firstChild==NULL){
            leaf++;
        }
    }
    return leaf;
}

template<class ElemType>
void ParentChildForest<ElemType>::Show()
{
    for(int i=0;i<=num;i++){
        cout<<i;
        cout<<"( "<<a[i].data<<", "<<a[i].parent<<", ";
        Child<ElemType> *p;
        if(a[i].firstChild==NULL){
            cout<<"^)"<<endl;
        }
        else{
            p=a[i].firstChild;
            while(p){
                cout<<" )->( "<<p->data<<", ";
                p=p->next;
            }
            cout<<"^)"<<endl;
        }
    }
}

#endif

运行结果:

完整可运行c++代码我已上传到公众号「会编程的z同学」,回复「森林」即可获取。