【数据结构笔记】2:基于树去建立森林的孩子-兄弟结构

来源:互联网 发布:美容软件app推荐 编辑:程序博客网 时间:2024/05/20 09:09

实现森林是这学期研讨1的内容,思路上不算复杂,实际操作起来发现原来自己已经很久没写C++了,非常手生,不过还是很快的完成了。但是发现自己对C++类的访问情况、友元、静态成员等概念已经非常生疏了,需要抽空补救一下。

设计要求:

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

基本思路:

因为树的孩子-兄弟表示模板老师已经给出来了,实际上森林的孩子兄弟表示法只要将一棵树的树根的nextSibling连接到下一棵树的树根上即可了。森林的先根、中根、后根遍历分别对应着森林的孩子-兄弟表示树基于二叉结构的先序中序后序遍历,需要注意的是因为它们是递归的,需要再设计一个递归封装的函数将它们封装起来。森林中树的数目只要遍历所有根节点即可(二叉结构不断向nextSibling走),最大高度也只要在遍历根节点过程中分别求树高即可,叶子数只要在遍历根节点过程中分别记录每棵树的叶子数加起来即可。

 

以下先补充一下树类中和本次设计相关的两个函数,这两个函数由于在森林类中需要调用(我采用的是先创建对象,再用对象调用之),所以应将访问类型修改为public类型的。

*补充:树类中求以r为根的树的高

template <class ElemType>int ChildSiblingTree<ElemType>::Height(ChildSiblingTreeNode<ElemType> *r) const// 操作结果: 求以r为根的树的高{ChildSiblingTreeNode<ElemType> *p;int k,max=-1;if (r != NULL){max=Height(FirstChild(r));for (p = FirstChild(r); p != NULL;p = NextSibling(p)){k=Height(p);if(k>max)max=k;}}return max+1;}

*补充:树类中求以r为根的树的叶子数

template <class ElemType>int ChildSiblingTree<ElemType>::LeafCount(ChildSiblingTreeNode<ElemType> *r) const// 操作结果: 求以r为根的树的叶子数{ChildSiblingTreeNode<ElemType> *p;int sum=0;if (r != NULL){if(r->firstChild==NULL)return 1;for (p = FirstChild(r); p != NULL;p = NextSibling(p)){if(p->firstChild==NULL)//如果它没有孩子(即是第一个孩子都没有)sum=sum+1;//那它就是叶子,叶子+1else//如果有孩子,那么总的叶子数是sum=LeafCount(p)+sum;//这个孩子对应子树的叶子数+已搜索完的当前兄弟中的叶子数}}return sum;}

*新增的森林类

#ifndef FOREST_H#define FOREST_H#include "child_sibling_tree.h"//import树类//森林类template<typename ElemType>class Forest{protected:ChildSiblingTreeNode<ElemType> *rootForest;//指向第一棵树的根节点//以下protected型方法均为辅助函数void Display(const ChildSiblingTreeNode<ElemType> *r,int level);//辅助显示一棵树ChildSiblingTreeNode<ElemType>* GetRoot()//返回森林根(第一棵树根){return rootForest;}//先根遍历以r为根的森林void PreRootOrder(ChildSiblingTreeNode<ElemType> *r, void (*Visit)(const ElemType &)) const{if (r != NULL){(*Visit)(r->data);// 访问根结点PreRootOrder(r->firstChild, Visit);//leftPreRootOrder(r->nextSibling, Visit);//right}}//中根遍历以r为根的森林void MidRootOrder(ChildSiblingTreeNode<ElemType> *r, void (*Visit)(const ElemType &)) const{if (r != NULL){MidRootOrder(r->firstChild, Visit);//left(*Visit)(r->data);// 访问根结点MidRootOrder(r->nextSibling, Visit);//right}}//后根遍历以r为根的森林void PostRootOrder(ChildSiblingTreeNode<ElemType> *r, void (*Visit)(const ElemType &)) const{if (r != NULL){PostRootOrder(r->firstChild, Visit);//leftPostRootOrder(r->nextSibling, Visit);//right(*Visit)(r->data);// 访问根结点}}public:Forest();//无参构造Forest(ChildSiblingTreeNode<ElemType> *root);//单个参数的构造void Settle(ChildSiblingTreeNode<ElemType> *root);//尾加一棵树void DisplayForest();//递归包装:显示本树void PreRootOrder(void (*Visit)(const ElemType &)) const//递归包装:先根遍历本树{PreRootOrder(rootForest, Visit);}void MidRootOrder(void (*Visit)(const ElemType &)) const//递归包装:中根遍历本树{MidRootOrder(rootForest, Visit);}void PostRootOrder(void (*Visit)(const ElemType &)) const//递归包装:后根遍历本树{PostRootOrder(rootForest, Visit);}int MaxHigh();//求森林中树的最大高度int SumLeaf();//求森林中总的叶子数};template<class ElemType>//辅助显示void Forest<ElemType>::Display(const ChildSiblingTreeNode<ElemType> *r,int level){ChildSiblingTreeNode<ElemType> *p;if (r!=NULL){cout<<endl;//显示新行for(int i = 0; i < level - 1; i++)cout<<"   ";//确保在第level列显示结点cout << r->data;//显示结点元素值for (p = r->firstChild; p != NULL;p = p->nextSibling)Display(p, level + 1);//依次显示各棵子树}}template<class ElemType>//递归包装并标准化显示森林void Forest<ElemType>::DisplayForest(){int count=0;for(ChildSiblingTreeNode<ElemType> *p=rootForest;p!=NULL;p=p->nextSibling){count++;cout<<endl<<"第"<<count<<"棵树是:"<<endl;Display(p,1);}cout<<endl<<"森林的规模为:"<<count<<endl;}template<class ElemType>//无参数构造Forest<ElemType>::Forest(){rootForest=NULL;}template<class ElemType>//单个参数构造Forest<ElemType>::Forest(ChildSiblingTreeNode<ElemType> *root){rootForest=root;}template<class ElemType>//尾加一棵树,这棵树根节点为rootvoid Forest<ElemType>::Settle(ChildSiblingTreeNode<ElemType> *root){if(rootForest==NULL)//特判{rootForest=root;return ;}ChildSiblingTreeNode<ElemType> *p;for(p=rootForest;p->nextSibling!=NULL;p=p->nextSibling);//运行至此p是最后一个节点p->nextSibling=root;//接上root即可}template<class ElemType>//求森林中树的最大高度int Forest<ElemType>::MaxHigh(){ChildSiblingTree<ElemType> a;//仅仅为了调用Height()方法if(rootForest==NULL)//特判return 0;int max=0,nowmax;for(ChildSiblingTreeNode<ElemType> *p=rootForest;p!=NULL;p=p->nextSibling)//遍历所有的树根{nowmax=a.Height(p);if(nowmax>max)max=nowmax;//不断更新找到最高树树高}return max;}template<class ElemType>int Forest<ElemType>::SumLeaf(){ChildSiblingTree<ElemType> a;//仅仅为了调用LeafCount()方法if(rootForest==NULL)//特判return 0;int sum=0;for(ChildSiblingTreeNode<ElemType> *p=rootForest;p!=NULL;p=p->nextSibling)//遍历所有的树根sum+=a.LeafCount(p);//每棵树的叶子数加起来即可return sum;}#endif

*主程序

#include "assistance.h"// 实用程序软件包#include "forest.h"//森林类int main(void){    try// 用try封装可能出现异常的代码{char items1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'};int parents1[] = {-1, 0, 0, 0, 1, 1, 3, 3};int n1 = 8;ChildSiblingTree<char> t1(items1, parents1, n1);char items2[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};int parents2[] = {-1, 0, 0, 1, 2, 3, 5, 5};int n2 = 8;ChildSiblingTree<char> t2(items2, parents2, n2);Forest<char> test;test.Settle(t1.GetRoot());//加入树t1test.Settle(t2.GetRoot());//加入树t2test.DisplayForest();//显示cout<<endl;cout << "先根序遍历森林:";test.PreRootOrder(Write);cout << endl;cout << "中根序遍历森林:";test.MidRootOrder(Write);cout << endl;cout << "后根序遍历森林:";test.PostRootOrder(Write);cout << endl<<endl;cout<<"森林的高度(最大树高)为:";cout<<test.MaxHigh()<<endl;cout<<"森林中总的叶子数为:";cout<<test.SumLeaf()<<endl;}catch (Error err)// 捕捉并处理异常{err.Show();// 显示异常信息}system("PAUSE");// 调用库函数system()return 0;// 返回值0, 返回操作系统}

运行结果:






0 0