createTree.h
#ifndef _CREATETREE_H_
#define _CREATETREE_H_
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
//树(森林)的双亲表示定义和算法--------------------------------------------
#define MAXLEN 100
typedef char elementType;
//树的结点结构
typedef struct pNode
{
elementType data; //结点数据域
int parent; //父结点指针(下标)
}PTNode;
//双亲表示的树(森林)结构
typedef struct pTree
{
PTNode node[MAXLEN]; //结点数组
int n; //结点总数
}pTree;
//初始化树
void initialTree(pTree &T)
{
T.n=0; //结点数初始化为0
}
//求祖先结点并输出
bool getAncestor(pTree &T, elementType x)
{
int w=0;
elementType y;
y=x;
for(w=0;w<T.n;w++)
{
if(T.node[w].data==y)
{
w=T.node[w].parent; //取得x的父结点
y=T.node[w].data; //取得父节点数据
cout<<y<<"\t"; //输出父节点
break;
}
}
if(w>=T.n) //x不在树上,返回false
return false;
//搜索x父结点之外的其它祖先结点
while(w!=-1) //搜索到根节点结束
{
if(T.node[w].data==y)
{
w=T.node[w].parent; //取得w的双亲结点下标
y=T.node[w].data; //获取双亲节点数据
cout<<y<<"\t"; //输出双亲节点数据
}
else
w=(w+1)%T.n; //w1上移
}
return true;
}
//求孩子结点
void getChildren(pTree &T, elementType x)
{
int i,w;
for(w=0;w<T.n;w++) //获取x在结点数组中的下标
{
if(T.node[w].data==x)
break;
}
if(w>=T.n) //x不在表中
return;
for(i=0;i<T.n;i++)
{
if(T.node[i].parent==w) //找到子结点,打印
cout<<T.node[i].data<<"\t";
}
cout<<endl;
}
//先序遍历
int firstChild(pTree &T,int v) //搜索下标(parent)为v的结点的第一个孩子结点下标
{
int w;
if(v==-1)
return -1;
for(w=0;w<T.n;w++)
{
if(T.node[w].parent==v)
return w;
}
return -1;
}
int nextSibling(pTree &T,int v,int w) //搜索v的下标位于w之后的下一个孩子结点下标
{
int i;
for(i=w+1;i<T.n;i++)
if(T.node[i].parent==v)
return i;
return -1;
}
void preOrder(pTree &T,int v)
{
int w;
cout<<T.node[v].data<<"\t";
w=firstChild(T,v);
while(w!=-1)
{
preOrder(T,w);
w=nextSibling(T,v,w);
}
}
void preTraverse(pTree &T)
{
int i;
int visited[MAXLEN];
for(i=0;i<T.n;i++)
{
visited[i]=0;
}
//搜索根结点,可能是森林,有多个根结点
for(i=0;i<T.n;i++)
{
if(T.node[i].parent==-1)
preOrder(T,i);
}
}
void postOrder(pTree &T,int v)
{
int w;
w=firstChild(T,v);
while(w!=-1)
{
postOrder(T,w);
w=nextSibling(T,v,w);
}
cout<<T.node[v].data<<"\t"; //访问根结点
}
void postTraverse(pTree &T)
{
int i;
int visited[MAXLEN];
for(i=0;i<T.n;i++)
{
visited[i]=0;
}
//搜索根结点,可能是森林,有多个根结点
for(i=0;i<T.n;i++)
{
if(T.node[i].parent==-1)
postOrder(T,i);
}
}
//打印树
void printTree(pTree &T)
{
int i;
cout<<"下标\t结点\t双亲"<<endl;
for(i=0;i<T.n;i++)
cout<<i<<"\t"<<T.node[i].data<<"\t"<<T.node[i].parent<<endl;
}
//双亲表示定义、算法结束---------------------------------------------------------------
//孩子兄弟链表表示定义、创建算法开始---------------------------------------------------
//树(森林)的孩子兄弟链表表示
typedef char elementType;
typedef struct csNode
{
elementType data;
struct csNode *firstChild, *nextSibling;
}csNode,*csTree;
//删除字符串、字符数组左边空格
void strLTrim(char* str)
{
int i,j;
int n=0;
n=strlen(str)+1;
for(i=0;i<n;i++)
{
if(str[i]!=' ') //找到左起第一个非空格位置
break;
}
//以第一个非空格字符为手字符移动字符串
for(j=0;j<n;j++)
{
str[j]=str[i];
i++;
}
}
//****************** 文件创建双亲表示的树(森林)********************//
//* 函数功能:从文本文件创建双亲表示的图 *//
//* 入口参数 char fileName[],数据文件名 *//
//* 出口参数:pTree &T,即创建的树 *//
//* 返 回 值:bool,true创建成功;false创建失败 *//
//* 函 数 名:CreateTreeFromFile(char fileName[], pTree &T) *//
//* 备注:本函数使用的数据文件格式以边(父子对)为基本数据 *//
//*******************************************************************//
int CreateTreeFromFile(char fileName[], pTree &T)
{
FILE* pFile; //定义顺序表的文件指针
char str[1000]; //存放读出一行文本的字符串
char strTemp[10]; //判断是否注释行
int i=0,j=0;
pFile=fopen(fileName,"r");
if(!pFile)
{
printf("错误:文件%s打开失败。\n",fileName);
return false;
}
while(fgets(str,1000,pFile)!=NULL) //跳过空行和注释行
{
strLTrim(str); //删除字符串左边空格
if (str[0]=='\n') //空行,继续读取下一行
continue;
strncpy(strTemp,str,2); //将str中的前两个字符拷贝到strTemp中
if(strstr(strTemp,"//")!=NULL) //跳过注释行
continue;
else //非注释行、非空行,跳出循环
break;
}
//循环结束,str中应该已经是文件标识,判断文件格式
if(strstr(str,"Tree or Forest")==NULL)
{
printf("错误:打开的文件格式错误!\n");
fclose(pFile); //关闭文件
return false;
}
//读取结点数据,到str。跳过空行
while(fgets(str,1000,pFile)!=NULL)
{
strLTrim(str); //删除字符串左边空格
if (str[0]=='\n') //空行,继续读取下一行
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL) //注释行,跳过,继续读取下一行
continue;
else //非空行,也非注释行,即图的顶点元素行
break;
}
//结点数据存入树的结点数组
char* token=strtok(str," ");
int nNum=0;
while(token!=NULL)
{
T.node[nNum].data=*token;
T.node[nNum].parent=-1; //父结点指针初始化为-1
token = strtok( NULL, " ");
nNum++;
}
//循环读取边(父子队)数据
int nP; //父结点数组下标
int nC; //子结点数组下标
elementType Nf,Ns; //父子结点对的两个结点
while(fgets(str,1000,pFile)!=NULL)
{
//删除字符串左边空格
strLTrim(str);
if (str[0]=='\n') //空行,继续读取下一行
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL) //注释行,跳过,继续读取下一行
continue;
char* token=strtok(str," "); //以空格为分隔符,分割一行数据,写入邻接矩阵
if(token==NULL) //分割为空串,失败退出
{
printf("错误:读取树的边数据失败!\n");
fclose(pFile); //关闭文件
return false;
}
Nf=*token; //获取父结点
token = strtok( NULL, " "); //读取下一个子串,即子结点
if(token==NULL) //分割为空串,失败退出
{
printf("错误:读取树的边数据失败!\n");
fclose(pFile); //关闭文件
return false;
}
Ns=*token; //获取边的第二个结点(子结点)
//取得父结点下标
for(nP=0;nP<nNum;nP++)
{
if(T.node[nP].data==Nf) //从顶点列表找到第一个顶点的编号
break;
}
//获取子结点的数组下标
for(nC=0;nC<nNum;nC++)
{
if(T.node[nC].data==Ns) //从顶点列表找到第二个顶点的编号
break;
}
T.node[nC].parent=nP; //nC的父结点的下标为nP
}
T.n=nNum; //树的结点数,即顶点数组的实际大小
fclose(pFile); //关闭文件
return true;
}
//搜索双亲表示中,下标w的下一个兄弟结点,返回兄弟结点的下标
int next(pTree T,int w)
{
int i;
for(i=w+1;i<T.n;i++)
{
if(T.node[w].parent==T.node[i].parent)
return i;
}
return -1;
}
//递归创建一棵孩子兄弟链表表示的树
void create(csNode *&T,pTree &T1,int v)
{
int w;
T=new csNode;
T->data=T1.node[v].data;
T->firstChild=NULL;
T->nextSibling=NULL;
w=firstChild(T1,v); //搜索v的第一个孩子结点
if(w!=-1)
{
create(T->firstChild,T1,w);
}
w=next(T1,v); //搜索v的下一个兄弟结点
if(w!=-1)
{
create(T->nextSibling,T1,w);
}
}
//从双亲表示的树(森林)创建孩子兄弟链表表示的树(森林)
void createCsTree(csNode *&T,pTree T1)
{
int i;
//搜索T1的第一个根结点
for(i=0;i<T1.n;i++)
{
if(T1.node[i].parent==-1) //找到第一个根结点
break;
}
if(i<T1.n)
create(T,T1,i);
}
//孩子兄弟链表表示定义、创建算法结束---------------------------------------------------
#endif // _CREATETREE_H
OperateTree.h
#ifndef _OPERATETREE_H
#define _OPERATETREE_H
#include <iostream>
#include "createTree.h"
#include <queue>
using namespace std;
//操作菜单
void menu()
{
cout<<"*************************************************"<<endl;
cout<<"0退出并销毁森林"<<endl;
cout<<"1数据文件创建森林"<<endl;
cout<<"2按先序、后序、层次遍历森林"<<endl;
cout<<"3求森林的高度"<<endl;
cout<<"4求森林结点总数"<<endl;
cout<<"5求森林叶子结点数"<<endl;
cout<<"6求森林的度"<<endl;
cout<<"7先序输出结点值及其层次号"<<endl;
cout<<"8输出广义表表示的树"<<endl;
cout<<"*************************************************"<<endl;
}
//先序遍历森林
void perOrderTraverse(csNode *T)
{
if(T)
{
cout<<T->data<<" "; //访问根节点
perOrderTraverse(T->firstChild); //递归调用先序遍历左子树
perOrderTraverse(T->nextSibling); //递归调用先序遍历右子树
}
}
//后序遍历森林
void postOrderTraverse(csNode *T)
{
if(T)
{
postOrderTraverse(T->firstChild); //递归调用先序遍历左子树
postOrderTraverse(T->nextSibling); //递归调用先序遍历右子树
cout<<T->data<<" "; //访问根节点
}
}
//层次遍历森林
void levelOrderTraverse(csNode *T)
{
queue<csNode *> q;
csNode * u,*n,*p;
if(T==NULL)
{
return;
}
n=T;
while(n)
{
p=n;
q.push(p);
while(!q.empty())
{
p=q.front();
cout<<p->data<<" ";
u=p->firstChild;
while(u)
{
p=u;
q.push(p);
u=u->nextSibling;
}
q.pop();
}
n=n->nextSibling;
}
}
//(2)求树的高度
int height(csNode *T)
{
int h,h1;
csNode *p;
if(T==NULL)
{
return 0;
}
else{
p=T->firstChild; //T->firstChild
h=height(p); //求根节点第一个孩子节点为根的子树高度
if(p)
p=p->nextSibling;
while(p)
{
h1=height(p); //求其兄弟节点的高度
if(h<h1)
h=h1; //h保存最高子树高度
p=p->nextSibling;
}
return 1+h; //返回森林的高度
}
}
//求森林的高度
int forestHeight(csNode *T)
{
int min,max=0; //max初始化为0
csNode *p;
p=T;
min=height(p);
while(p) //循环控制访问其他树的根节点
{
if(min>max)
max=min; //保存各树的最大高度
p=p->nextSibling;
min=height(p); //返回最大高度
}
return max;
}
//(3)求森林结点总数
void getNodeNumber(csNode *T,int &NodeNum)
{
if(T)
{
NodeNum++;
getNodeNumber(T->firstChild,NodeNum);
getNodeNumber(T->nextSibling,NodeNum);
}
}
//(4)求森林叶子结点数
void leafNodeNum(csNode *T,int &leafNum)
{
if(T)
{
if(T->firstChild==NULL)
leafNum++;
leafNodeNum(T->firstChild,leafNum);
leafNodeNum(T->nextSibling,leafNum);
}
}
//(5)求森林的度
int degreeOfForest(csNode *T)
{
queue<csNode *> q;
csNode * u,*n,*p;
int min=1,max=0;
if(T==NULL)
{
return 0;
}
n=T;
while(n)
{
p=n;
q.push(p);
while(!q.empty())
{
p=q.front();
u=p->firstChild;
while(u)
{
p=u;
q.push(p);
u=u->nextSibling;
min++;
}
if(min>max)
{
max=min;
}
min=1;
q.pop();
}
n=n->nextSibling;
}
return max-1;
}
//(6)先序输出结点值及其层次号
void outPreOrder(csNode *T,int level)
{
if(T)
{
cout<<"("<<T->data<<","<<level<<")"<<" ";
outPreOrder(T->firstChild,level+1);
outPreOrder(T->nextSibling,level);
}
}
//(7)输出广义表表示的树
void outGList(csNode *T)
{
if(T)
{
cout<<T->data;
if(T->firstChild)
{
cout<<"(";
outGList(T->firstChild);
}
if(T->nextSibling)
{
cout<<",";
outGList(T->nextSibling);
}
else{
cout<<")";
}
}
}
//销毁森林
void destroy(csNode *&T)
{
if(T)
{
destroy(T->firstChild);
destroy(T->nextSibling);
delete T;
}
}
#endif // _OPERATETREE_H
主函数
```c
#include <iostream>
#include <Cstdlib>
#include "createTree.h"
#include "OperateTree.h"
using namespace std;
int main()
{
pTree T1;
csNode *T;
int i;
char fileName[100]; //保存文件名
int high; //保存树的高度
int NodeNum=0; //保存节点个数,初始化为0
int leafNum=0; //保存叶子个数,初始化为0
int degree; //保存森林的度
int level=1; //森林层数,初始化为1
menu();
cout<<"请输入执行序号:";
cin>>i;
while(i)
{
switch(i)
{
case 1:
cout<<"请输入打开的文件名:";
cin>>fileName;
if(CreateTreeFromFile(fileName, T1))
{
cout<<"数据处理完毕!"<<endl;
}
createCsTree(T,T1);
break;
case 2:
cout<<"先序序列为:";
perOrderTraverse(T);
cout<<endl;
cout<<"后序序列为:";
postOrderTraverse(T);
cout<<endl;
cout<<"层次序列为:";
levelOrderTraverse(T);
cout<<endl;
break;
case 3:
high=forestHeight(T);
cout<<"树的高度为:"<<high<<endl;
break;
case 4:
getNodeNumber(T,NodeNum);
cout<<"节点总数为:"<<NodeNum<<endl;
break;
case 5:
leafNodeNum(T,leafNum);
cout<<"叶子节点总数为:"<<leafNum<<endl;
break;
case 6:
degree=degreeOfForest(T);
cout<<"森林的度为:"<<degree<<endl;
break;
case 7:
outPreOrder(T,level);
cout<<endl;
break;
case 8:
cout<<"广义表为:"<<"(";
outGList(T);
cout<<endl;
break;
}
system("PAUSE");
system("CLS");
menu();
cout<<"请输入执行序号:";
cin>>i;
}
destroy(T);
return 0;
}