二叉树(C++模板实现)

一、实验要求

   <1>打印出二叉树的三种遍历序。

    <2>设计算法按中序次序输出二叉树中各结点的值及其所对应的层次数。

    <3>求二叉树的高度。

    <4>求二叉树的结点数。

    <5>求二叉树的叶子结点数。

    <6>求二叉树的度为2的结点数。

    <7>键盘输入一个元素x,求其父节点、兄弟结点、子结点的值,不存在时给出相应提示信息。对兄弟结点和孩子结点,存在时要明确指出是左兄弟、左孩子、右兄弟或右孩子。

    <8>键盘输入一个元素x,求其在树中的层次。不存在时给出相应提示信息。

    <9>将按顺序方式存储在数组中的二叉树转换为二叉链表形式。(数组中要扩展为完全二叉树)。

    <10>交换二叉树中每个结点的左右孩子指针的值。(即:左子树变为右子树,右子树变为左子树)。

     <11>复制一棵二叉树T到T1。(选做题

     <12>输出二叉树从每个叶子结点到根结点的路径。(选做题

     <13>对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印。(选做题

     <14>对二叉链表表示的二叉树,求2个结点最近的共同祖先。(选做题

     <15>求二叉树中一条最长的路径长度(边数),并输出路径上的个结点值。(选做题

二、数据结构设计

template<class ElementType>
struct Node{
    ElementType data;             //数据域
    struct Node * lchild;         //左孩子指针
    struct Node * rchild;         //右孩子指针
};
//二叉树的封装如下:
template<class ElementType>
class BiTree{
public:
//初始化
BiTree(Node <ElementType> *&T);  
	//销毁树                           
void destory(Node <ElementType> *&pBT);                     
//二叉树操作菜单
static void menu();  
//从文件读取数据    
bool ReadFileToArray(char fileName[],char strLine[100][3],int & nLen); 
	//从文件创建二叉树                      
bool CreatBiTreeFromFile(Node<ElementType>*&pBT,char strLine[100][3],int nLen,int & nRow); 
//创建子树函数
void createSubTree(Node <ElementType> * p,int k);          
//创建二叉树函数
void createBiTree(Node <ElementType> *&T);                  
	//先序遍历算法
void perOrderTraverse(Node <ElementType> * T);             
	//中序遍历算法
 void inOrderTraverse(Node <ElementType> * T); 
//后序遍历算法              
 void postOrderTraverse(Node <ElementType> * T);
//中序次序输出二叉树中各结点的值及其所对应的层次数             
 void outOrderTraverse(Node <ElementType> * T,int level);    
//求树的高度
 int BiTreeDepth(Node <ElementType> * T);  
//求二叉树的结点数                  
 void GetNodeNumber(Node <ElementType> * T,int &nNodeNum);  
//求二叉树的叶子结点数 
 void leafNodeNum(Node <ElementType> *T,int &nNodeNum); 
//求二叉树的度为2的结点数    
 void TwoBranchNodeNum(Node <ElementType> *T,int &nNodeNum); 
//键盘输入一个元素x,求其父节点、兄弟结点、子结点的值,不存在时给出相应提示信息。对兄弟结点和孩子结点,存在时要明确指出是左兄弟、左孩子、右兄弟或右孩子
void GetFatherBrotherChildNode(Node <ElementType> *T,ElementType x);  
//键盘输入一个元素x,求其在树中的层次。不存在时给出相应提示信息
void GetNodeLevel(Node <ElementType> *T,ElementType x,int level,int &flag); 
//将按顺序方式存储在数组中的二叉树转换为二叉链表形式。(数组中要扩展为完全二叉树)
void ArrayToBiTree(Node <ElementType> *&T,ElementType A[],int i,int num); 
//交换二叉树中每个结点的左右孩子指针的值  
void ExchangeTree(Node <ElementType> * & T)
//二叉树转数组
void BiTreeToArray(Node <ElementType> *T,ElementType A[],int i,int &count); 
//输出二叉树从每个叶子结点到根结点的路径
 void PrintRoute(Node <ElementType> *T,ElementType path[],int pathLen);
//对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印      
void LevelTraverse(Node <ElementType> *T,ElementType B[],int num);   
//遍历查找节点x,并把路径保存在栈s中  
void SearchBiTree(Node <ElementType> * T,Stack <Node <ElementType> * > & s,
ElementType x)  
//求二叉树中一条最长的路径长度(边数),并输出路径上的结点值
void PrintMaxLenPath(Node <ElementType> *T,int MaxLen);  
//非递归输出二叉树从每个叶子结点到根结点的路径(选做题)
void PrintAllPath(Node <ElementType> *T);                   
private:
    Node<ElementType> *pBT;    //根节点指针
};

三、算法设计

  1. 设计算法按中序次序输出二叉树中各结点的值及其所对应的层次数

算法思想:改造中序遍历算法,增加一个计算层次的变量level,初始化为1。每次访问根节点并输出结点的值和层数,每次递归调用时level++。

      2.求二叉树的叶子结点数

算法思想:改造前序、中序、后序遍历算法,增加一个计算结点数的变量NodeNum,每次访问根节点时,如果T的没有左孩子和右孩子,NodeNum++。

      3.键盘输入一个元素x,求其父节点、兄弟结点、子结点的值,不存在时给出相应提示信息。对兄弟结点和孩子结点,存在时要明确指出是左兄弟、左孩子、右兄弟或右孩子

算法思想:改造前序、中序、后序遍历算法,键盘输入一个元素x,判断T->lchild->data==x或T->rchild->data==x,如果相等,再判断是否有左右孩子T->lchild->lchild==NULL和T->lchild->rchild==NULL或T->rchild->lchild==NULL或T->rchild->rchild==NULL,如果存在,则输出父节点T->data,左兄弟T->lchild->data或右兄弟T->rchild->data,左孩子T->lchild->lchild->data或T->rchild->lchild->data,右孩子T->lchild->lchild->data或T->rchild->rchild->data。

     4.键盘输入一个元素x,求其在树中的层次。不存在时给出相应提示信息

算法思想:改造前序、中序、后序遍历算法,增加一个计算层次的变量level,初始化为1。每次访问根节点时,如果T->data==x,则输出level即可。每次递归调用时level++。

    5.将按顺序方式存储在数组中的二叉树转换为二叉链表形式。(数组中要扩展为完全二叉树)

算法思想:改造二叉树的一种遍历算法完成,这里改造先序遍历实现。算法包括两个整型参数i和num。i为结点在完全二叉树上的编号,从1开始;num为二叉树上最后有效结点编号。

    6.交换二叉树中每个结点的左右孩子指针的值。(即:左子树变为右子树,右子树变为左子树)

算法思想:改造二叉树的一种遍历算法完成,每次访问根节点时,互换左右孩子指针即可。

    7.复制一棵二叉树T到T1

算法思想:将二叉树T转换为数组,再将数组还原成二叉树T1

    8.输出二叉树从每个叶子结点到根结点的路径(经历的结点)

算法思想:改造二叉树的非递归形式的后序遍历,如果p为根节点,遍历输出栈内元素,直到右子树遍历完成。

    9.对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印。

算法思想:设一个数组A[]初始化为0,将二叉树转化为数组存入A数组中,在控制数组A的树形输出即可。

    10.对二叉链表表示的二叉树,求2个结点最近的共同祖先

算法思想:把两个节点到根节点的路径分别保存到两个栈中,栈元素个数多的出栈,直到第一次两个栈中的栈顶元素相等且栈中元素个数相等。即栈顶元素为两个根节点的祖先。

    11.求二叉树中一条最长的路径长度(边数),并输出路径上的个结点值

算法思想:先用递归求出树的高度,再用改造后序遍历的非递归算法,如果栈中的元素个数等于输的高度,输出栈内元素,继续遍历直到右子树遍历完成。

四、代码实现

#ifndef _SEQSTACK_H_
#define _SEQSTACK_H_
#include <iostream>
#define MAXLEN 100

using namespace std;

template<class ElementType>
class Stack{
public :
    Stack();                    //初始化栈
    ~Stack();                   //销毁栈
    int empty();                //判断栈是否为空
    int pop(ElementType & x);   //出栈
    int push(ElementType x);    //压栈
    ElementType top();          //取栈顶元素
    ElementType getData(int i); //获取第i个数据
    int getLen();               //获取栈长度
private :
    ElementType * data;         //栈数据储存
    int len;                    //栈当前元素个数
   // int size;                 //栈的大小
};
//构造函数,初始化栈
template<class ElementType>
Stack<ElementType>::Stack()
{
    data=new ElementType[MAXLEN];
    len=0;
}
//析构函数,销毁栈
template<class ElementType>
Stack<ElementType>::~Stack()
{
    delete [] data;
}
//判断栈是否为空
template<class ElementType>
int Stack<ElementType>::empty()
{
    if(len==0)
    {
        return 1;
    }
    else{
        return 0;
    }
}
 //出栈,成功返回1,否则返回0
template<class ElementType>
int Stack<ElementType>::pop(ElementType & x)
{
    if(len==0)
    {
        return 0;
    }
    else{
        x=data[len-1];
        len--;
        return 1;
    }
}
//压栈
template<class ElementType>
int Stack<ElementType>::push(ElementType x)
{
    if(len==MAXLEN)
    {
        return 0;
    }
    else{
        len++;
        data[len-1]=x;
        return 1;
    }
}
//取栈顶元素
template<class ElementType>
ElementType Stack<ElementType>::top()
{
    if(empty())
    {
        return NULL;
    }
    else{
        return data[len-1];
    }

}
//遍历栈
template<class ElementType>
ElementType Stack<ElementType>::getData(int i)
{
        return data[i];
}
 //获取栈长度
template<class ElementType>
int Stack<ElementType>::getLen()
{
    return len;
}
#endif // _SEQSTACK_H_
#ifndef _BITREE_H_
#define _BITREE_H_
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include "seqStack.h"
#include <cmath>

using namespace std;

template<class ElementType>
struct Node{
    ElementType data;             //数据域
    struct Node * lChild;         //左孩子指针
    struct Node * rChild;         //右孩子指针
};
template<class ElementType>
class BiTree{
public:
    BiTree(Node <ElementType> *&T);                             //初始化
    void destory(Node <ElementType> *&pBT);                     //销毁树
    static void menu();                                         //二叉树操作菜单
    bool ReadFileToArray(char fileName[],char strLine[100][3],int & nLen);                       //从文件读取数据
    bool CreatBiTreeFromFile(Node<ElementType> *&pBT,char strLine[100][3],int nLen,int & nRow);  //从文件创建二叉树
    void createSubTree(Node <ElementType> * p,int k);           //创建子树函数
    void createBiTree(Node <ElementType> *&T);                  //创建二叉树函数
    void perOrderTraverse(Node <ElementType> * T);              //先序遍历算法
    void inOrderTraverse(Node <ElementType> * T);               //中序遍历算法
    void postOrderTraverse(Node <ElementType> * T);             //后序遍历算法
    void outOrderTraverse(Node <ElementType> * T,int level);    //中序次序输出二叉树中各结点的值及其所对应的层次数
    int BiTreeDepth(Node <ElementType> * T);                    //求树的高度
    void GetNodeNumber(Node <ElementType> * T,int &nNodeNum);   //求二叉树的结点数
    void leafNodeNum(Node <ElementType> *T,int &nNodeNum);      //求二叉树的叶子结点数
    void TwoBranchNodeNum(Node <ElementType> *T,int &nNodeNum); //求二叉树的度为2的结点数
    void GetFatherBrotherChildNode(Node <ElementType> *T,ElementType x);        //键盘输入一个元素x,求其父节点、兄弟结点、子结点的值,不存在时给出相应提示信息。对兄弟结点和孩子结点,存在时要明确指出是左兄弟、左孩子、右兄弟或右孩子
    void GetNodeLevel(Node <ElementType> *T,ElementType x,int level,int &flag); //键盘输入一个元素x,求其在树中的层次。不存在时给出相应提示信息
    void ArrayToBiTree(Node <ElementType> *&T,ElementType A[],int i,int num);   //将按顺序方式存储在数组中的二叉树转换为二叉链表形式。(数组中要扩展为完全二叉树)
    void ExchangeTree(Node <ElementType> *&T);                                  //交换二叉树中每个结点的左右孩子指针的值
    void BiTreeToArray(Node <ElementType> *T,ElementType A[],int i,int &count); //二叉树转数组
    void PrintRoute(Node <ElementType> *T,ElementType path[],int pathLen);      //输出二叉树从每个叶子结点到根结点的路径
    void LevelTraverse(Node <ElementType> *T,ElementType B[],int num);       //对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印
    void SearchBiTree(Node <ElementType> *T,Stack<Node <ElementType> *> &s,ElementType x);  //遍历查找节点x,并把路径保存在栈s中
    void PrintMaxLenPath(Node <ElementType> *T,int MaxLen);     //求二叉树中一条最长的路径长度(边数),并输出路径上的结点值
    void PrintAllPath(Node <ElementType> *T);                   //非递归输出二叉树从每个叶子结点到根结点的路径(选做题)
private:
    Node<ElementType> *pBT;    //根节点指针
};
//初始化
template<class ElementType>
BiTree<ElementType>::BiTree(Node <ElementType> *&T)
{
    pBT=T;
}
//销毁树
template<class ElementType>
void BiTree<ElementType>::destory(Node <ElementType> *&pBT)
{
    if(pBT)
    {
        destory((pBT)->lChild);
        destory((pBT)->rChild);
        delete pBT;
    }
}
//二叉树操作菜单
template<class ElementType>
void BiTree<ElementType>::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求二叉树的度为2的结点数"<<endl;
    cout<<"9键盘输入一个元素x,求其父节点、兄弟结点、孩子结点的值"<<endl;
    cout<<"10键盘输入一个元素x,求其在树中的层次"<<endl;
    cout<<"11将按顺序方式存储在数组中的二叉树转换为二叉链表形式"<<endl;
    cout<<"12交换二叉树中每个结点的左右孩子指针的值"<<endl;
    cout<<"13复制一棵二叉树T到T1(选做题)"<<endl;
    cout<<"14递归输出二叉树从每个叶子结点到根结点的路径(选做题)"<<endl;
    cout<<"15对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印(选做题)"<<endl;
    cout<<"16对二叉链表表示的二叉树,求2个结点最近的共同祖先(选做题)"<<endl;
    cout<<"17求二叉树中一条最长的路径长度(边数),并输出路径上的个结点值(选做题)"<<endl;
    cout<<"18非递归输出二叉树从每个叶子结点到根结点的路径(选做题)"<<endl;
    cout<<"*************************************************"<<endl;
}
//从文件读取数据
template<class ElementType>
bool BiTree<ElementType>::ReadFileToArray(char fileName[],char strLine[100][3],int & nLen)
{
    FILE *pFile;      //定义二叉树文件指针
    char str[1000];   //存放读取一行文本的字符串
    pFile=fopen(fileName,"r");
    if(!pFile)
    {
        cout<<"文件打开失败!"<<endl;
        return false;
    }
    //读取文件第一行,判断二叉树标识BinaryTree是否正确
    if(fgets(str,1000,pFile)!=NULL)
    {
        if(strcmp(str,"BinaryTree\n")!=0)
        {
            cout<<"打开的文件格式错误!"<<endl;
            fclose(pFile);
            return false;
        }
    }
    nLen=1;
    while(fscanf(pFile,"%c %c %c\n",&strLine[nLen][0],&strLine[nLen][1],&strLine[nLen][2])!=EOF)
    {
        nLen++;
    }
    fclose(pFile);
    return true;
}
//从文件创建二叉树
template<class ElementType>
bool BiTree<ElementType>::CreatBiTreeFromFile(Node<ElementType> *&pBT,char strLine[100][3],int nLen,int & nRow)
{
    if((nRow>=nLen)||(nRow==0))
    {
        return false;          //数据已处理完毕,或者没有数据
    }
    //根据数组数据递归创建二叉树
    pBT=new Node <ElementType>  ;
    pBT->data=strLine[nRow][0];
    pBT->lChild=NULL;           //初始化左孩子为空
    pBT->rChild=NULL;           //初始化右孩子为空
    int nRowNext=nRow;          //保留本次递归的行号
    if(strLine[nRowNext][1]=='1')
    {
        nRow++;                  //行号加一
        CreatBiTreeFromFile(pBT->lChild,strLine,nLen,nRow);   //递归创建左子树

    }
    if(strLine[nRowNext][2]=='1')
    {
        nRow++;                  //行号加一
        CreatBiTreeFromFile(pBT->rChild,strLine,nLen,nRow);     //递归创建右子树
    }
    return true;
}
//创建子树函数
template<class ElementType>
void BiTree<ElementType>::createSubTree(Node <ElementType> * p,int k)
{
    //q为当前节点
    //k=1时为左子树
    Node <ElementType> * u;
    ElementType x;
    cin>>x;                     //键盘读入节点数据
    if(x!='/')                 //x='/'表示没有左子树
    {
        u=new Node <ElementType>;
        u->data=x;
        u->lChild=NULL;
        u->rChild=NULL;
        if(k==1)
        {
            p->lChild=u;        //新节点为当前根节点q的左子树
        }
        if(k==2)
        {
            p->rChild=u;        //新节点为当前根节点q的右子树
        }
        createSubTree(u,1);     //递归创建u的左子树
        createSubTree(u,2);     //递归创建u的右子树
    }
}
//创建二叉树函数
template<class ElementType>
void BiTree<ElementType>::createBiTree(Node <ElementType> *&T)
{
    Node <ElementType> * p;
    ElementType x;
    cout<<"请按先序序列依次输入二叉树(‘/’为无子树)"<<endl;
    cin>>x;
    if(x=='/')
        return ;        //空树,退出
     T=new Node <char>;
     T->data=x;
     T->lChild=NULL;
     T->rChild=NULL;
     p=T;
     createSubTree(p,1);     //创建根节点左子树
     createSubTree(p,2);     //创建根节点右子树
}
//先序遍历算法
template<class ElementType>
void BiTree<ElementType>::perOrderTraverse(Node <ElementType> * T)
{
    if(T)
    {
        cout<<T->data<<" ";           //访问根节点
        perOrderTraverse(T->lChild);  //递归调用先序遍历左子树rChild
        perOrderTraverse(T->rChild);  //递归调用先序遍历右子树
    }
}
//中序遍历算法
template<class ElementType>
void BiTree<ElementType>::inOrderTraverse(Node <ElementType> * T)
{
    if(T)
    {
        inOrderTraverse(T->lChild);  //递归调用先序遍历左子树
        cout<<T->data<<" ";          //访问根节点
        inOrderTraverse(T->rChild);  //递归调用先序遍历右子树
    }
}
//后序遍历算法
template<class ElementType>
void BiTree<ElementType>::postOrderTraverse(Node <ElementType> * T)
{
    if(T)
    {
        postOrderTraverse(T->lChild);  //递归调用先序遍历左子树
        postOrderTraverse(T->rChild);  //递归调用先序遍历右子树
        cout<<T->data<<" ";            //访问根节点
    }
}
//中序次序输出二叉树中各结点的值及其所对应的层次数
template<class ElementType>
void BiTree<ElementType>::outOrderTraverse(Node <ElementType> * T,int level)
{
    if(T)
    {
        outOrderTraverse(T->lChild,level+1);  //递归调用先序遍历左子树
        cout<<"("<<T->data<<","<<level<<")"<<endl;       //访问根节点,并输出层数
        outOrderTraverse(T->rChild,level+1);  //递归调用先序遍历右子树
    }
}
//求树的高度
template<class ElementType>
int BiTree<ElementType>::BiTreeDepth(Node <ElementType> * T)
{
    int m,n;
    if(T==NULL)
        return 0;           //空树,高度为0
    else{
        m=BiTreeDepth(T->lChild);   //求左子树高度(递归)
        n=BiTreeDepth(T->rChild);   //求右子树高度(递归)
        if(m>n)
        {
            return m+1;
        }
        else{
            return n+1;
        }
    }
}
//求二叉树的结点数
template<class ElementType>
void BiTree<ElementType>::GetNodeNumber(Node <ElementType> * T,int &nNodeNum)
{
    if(T!=NULL)
    {
        GetNodeNumber(T->lChild,nNodeNum);
        nNodeNum++;
        GetNodeNumber(T->rChild,nNodeNum);
    }
}
//求二叉树的叶子结点数。
template<class ElementType>
void BiTree<ElementType>::leafNodeNum(Node <ElementType> *T,int &nNodeNum)
{
    if(T!=NULL)
    {
        leafNodeNum(T->lChild,nNodeNum);
        if(T->lChild==NULL&&T->rChild==NULL)
        {
            nNodeNum++;
        }
        leafNodeNum(T->rChild,nNodeNum);
    }
}
//求二叉树的度为2的结点数
template<class ElementType>
void BiTree<ElementType>::TwoBranchNodeNum(Node <ElementType> *T,int &nNodeNum)
{
    if(T!=NULL)
    {
        TwoBranchNodeNum(T->lChild,nNodeNum);
        if(T->lChild!=NULL&&T->rChild!=NULL)
        {
            nNodeNum++;
        }
        TwoBranchNodeNum(T->rChild,nNodeNum);
    }
}
//键盘输入一个元素x,求其父节点、兄弟结点、子结点的值,不存在时给出相应提示信息。对兄弟结点和孩子结点,存在时要明确指出是左兄弟、左孩子、右兄弟或右孩子
template<class ElementType>
void BiTree<ElementType>::GetFatherBrotherChildNode(Node <ElementType> *T,ElementType x)
{
    if(T)
    {
        if(T->lChild!=NULL)
        {
            if(T->lChild->data==x)
            {
                cout<<"父节点的值为:"<<T->data<<endl;   //输出父节点的值
                if(T->rChild==NULL)
                {
                    cout<<"右兄弟不存在!"<<endl;        //判断右兄弟是否存在,存在输出其值
                }
                else{
                    cout<<"右兄第为:"<<T->rChild->data<<endl;
                }
                if(T->lChild->lChild==NULL)
                {
                    cout<<"左孩子不存在!"<<endl;
                }
                else{
                    cout<<"左孩子为:"<<T->lChild->lChild->data<<endl;
                }
                if(T->lChild->rChild==NULL)
                {
                    cout<<"右孩子不存在!"<<endl;
                }
                else{
                    cout<<"右孩子为:"<<T->lChild->lChild->data<<endl;
                }
            }
        }
        if(T->rChild!=NULL)
        {
            if(T->rChild->data==x)
            {
                cout<<"父节点的值为:"<<T->data<<endl;   //输出父节点的值
                if(T->lChild==NULL)
                {
                    cout<<"左兄弟不存在!"<<endl;        //判断左兄弟是否存在,存在输出其值
                }
                else{
                    cout<<"左兄第为:"<<T->lChild->data<<endl;
                }
                if(T->rChild->lChild==NULL)
                {
                    cout<<"左孩子不存在!"<<endl;
                }
                else{
                    cout<<"左孩子为:"<<T->rChild->lChild->data<<endl;
                }
                if(T->rChild->rChild==NULL)
                {
                    cout<<"右孩子不存在!"<<endl;
                }
                else{
                    cout<<"右孩子为:"<<T->rChild->rChild->data<<endl;
                }
            }
        }
        GetFatherBrotherChildNode(T->lChild,x);
        GetFatherBrotherChildNode(T->rChild,x);
    }
}
//键盘输入一个元素x,求其在树中的层次。不存在时给出相应提示信息
template<class ElementType>
void BiTree<ElementType>::GetNodeLevel(Node <ElementType> * T,ElementType x,int  level,int & flag)
{
    if(T!=NULL)
    {
        GetNodeLevel(T->lChild,x,level+1,flag);
        if(T->data==x)
        {
            cout<<"该节点层次为:"<<level<<endl;
            flag=1;
        }
        GetNodeLevel(T->rChild,x,level+1,flag);
    }
}
//将按顺序方式存储在数组中的二叉树转换为二叉链表形式。(数组中要扩展为完全二叉树)
template<class ElementType>
void BiTree<ElementType>::ArrayToBiTree(Node <ElementType> *&T,ElementType A[],int i,int num)
{
    if(i<=num&&A[i])
    {
        T=new Node <ElementType>;
        if(A[i]!='0')
        T->data=A[i];
        T->lChild=NULL;
        T->rChild=NULL;
        ArrayToBiTree(T->lChild,A,2*i,num);
        ArrayToBiTree(T->rChild,A,2*i+1,num);
    }
}
//交换二叉树中每个结点的左右孩子指针的值
template<class ElementType>
void BiTree<ElementType>::ExchangeTree(Node <ElementType> *&T)
{
    Node <ElementType> * temp;
    if(T!=NULL)
    {
        temp=T->lChild;
        T->lChild=T->rChild;
        T->rChild=temp;
        ExchangeTree(T->lChild);
        ExchangeTree(T->rChild);
    }
}
//二叉树转数组
template<class ElementType>
void BiTree<ElementType>::BiTreeToArray(Node <ElementType> *T,ElementType A[],int i,int &count)
{
    if(T!=NULL)
    {
        A[i]=T->data;
        if(i>count)
            count=i;
        BiTreeToArray(T->lChild,A,2*i,count);
        BiTreeToArray(T->rChild,A,2*i+1,count);
    }
}
//输出二叉树从每个叶子结点到根结点的路径
template<class ElementType>
void BiTree<ElementType>::PrintRoute(Node <ElementType> *T,ElementType path[],int pathLen)
{
    int i;
    if(T!=NULL)
    {
        if(T->lChild==NULL&&T->rChild==NULL)
        {
            cout<<T->data<<"到根节点的路径为:"<<T->data<<" ";
            for(i=pathLen-1;i>=0;i--)
            {
                cout<<path[i]<<" ";
            }
            cout<<endl;
        }
         else{
            path[pathLen]=T->data;
            pathLen++;
            PrintRoute(T->lChild,path,pathLen);
            PrintRoute(T->rChild,path,pathLen);
            pathLen--;
        }
    }
}
//对二叉链表表示的二叉树,按从上到下,从左到右打印结点值,即按层次打印
template<class ElementType>
void BiTree<ElementType>::LevelTraverse(Node <ElementType> *T,ElementType B[],int num)
{
    int n,i,j,t,q,s,p,m=0,k=0;
    n=(int)((log(num)/log(2))+1);
    p=n;
    for(i=0;i<n;i++)
    {
        k=pow(2,m)+k;
        t=pow(2,m);
        j=pow(2,p-1)-1;
        q=pow(2,p)-1;
        s=q;
        for(j;j>0;j--)
        {
            cout<<" ";
        }
        for(t;t<=k;t++)
        {
            if(B[t]==0)
            {
                cout<<"*";
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
            else{
                cout<<B[t];
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
        }
        m++;
        p--;
        j=n-i-1;
        cout<<endl;
    }
}
//遍历查找节点x,并把路径保存在栈s中
template<class ElementType>
void BiTree<ElementType>::SearchBiTree(Node <ElementType> *T,Stack<Node <ElementType> *> &s,ElementType x)
{
    Node <ElementType> *p;
    int tag[100];
    p=T;
    while(p||!s.empty())
    {
        if(p)
        {
            s.push(p);
            tag[s.getLen()-1]=0;
            if(p->data==x)
            {
                break;
            }
            else{
            p=p->lChild;
            }
        }
        else{
            p=s.top();
            if(tag[s.getLen()-1]==0)
            {
                tag[s.getLen()-1]=1;
                p=p->rChild;
            }
            else{
                s.pop(p);
                p=NULL;
            }
        }
    }
}
//求二叉树中一条最长的路径长度(边数),并输出路径上的结点值
template<class ElementType>
void BiTree<ElementType>::PrintMaxLenPath(Node <ElementType> *T,int MaxLen)
{
    Node <ElementType> *p;
    Stack<Node <ElementType> *> s;
    int t=MaxLen;
    int tag[100];
    p=T;
    while(p||!s.empty())
    {
        if(p)
        {
            s.push(p);
            tag[s.getLen()-1]=0;
            if(s.getLen()==MaxLen)
            {
                cout<<"最长路径长度为:"<<MaxLen<<endl;
                cout<<"最长路径为:";
                while(MaxLen)
                {
                    cout<<s.getData(MaxLen-1)->data<<" ";
                    MaxLen--;
                }
                cout<<endl;
                MaxLen=t;
                p=p->lChild;
            }
            else{
                p=p->lChild;
            }
        }
        else{
            p=s.top();
            if(tag[s.getLen()-1]==0)
            {
                tag[s.getLen()-1]=1;
                p=p->rChild;
            }
            else{
                s.pop(p);
                p=NULL;
            }
        }
    }
}
//非递归输出二叉树从每个叶子结点到根结点的路径(选做题)
template<class ElementType>
void BiTree<ElementType>::PrintAllPath(Node <ElementType> *T)
{
    Node <ElementType> *p;
    Stack<Node <ElementType> *> s;
    int t;
    int tag[100];
    p=T;
    while(p||!s.empty())
    {
        if(p)
        {
            s.push(p);
            tag[s.getLen()-1]=0;
            t=s.getLen();
            if(p->lChild==NULL&&p->rChild==NULL)
            {
                cout<<p->data<<"到根节点路径为:";
                while(t)
                {
                    cout<<s.getData(t-1)->data<<" ";
                    t--;
                }
                cout<<endl;
                p=p->lChild;
            }
            else{
                p=p->lChild;
            }
        }
        else{
            p=s.top();
            if(tag[s.getLen()-1]==0)
            {
                tag[s.getLen()-1]=1;
                p=p->rChild;
            }
            else{
                s.pop(p);
                p=NULL;
            }
        }
    }
}
#endif // _BITREE_H_
#include <iostream>
#include <Cstdlib>
#include "BiTree.h"
#include "seqStack.h"

using namespace std;

int main()
{
    int x;
    Node <char> * root=NULL;    //定义根节点root
    Node <char> *c,d;
    BiTree <char> T(root);      //初始化
    Node <char> * root1=NULL;   //定义根节点root1
    BiTree <char> T1(root1);    //初始化
    char fileName[100];         //保存文件名
    char strLine[100][3];       //保存二叉树文件数据
    int  nLen;                  //保存节点个数
    int nRow=1;                 //当前行数
    int level=1;                //表示二叉树的层次
    int nNodeNum=0;             //节点总数
    int leafNodeNum=0;          //保存叶子节点数,初始化为0
    int TwoBranchNodeNum=0;     //保存度为2的节点,初始化为0
    char y,z;               //保存输入元素
    int flag=0;                 //标志位,初始化为0
    char A[100]={0};            //顺序二叉树
    char B[100]={0};
    int i=1;                    //数组下标,初始化为1
    int num=0;                  //第num个有效下标,初始化为0
    int count=1;                //记录树中节点个数
    int pathLen=0;              //存放路径长度
    int nLayer=1;               //深度为一层
    Stack<Node <char> *> s1,s2; //定义两个栈
    int maxLen;
    BiTree <char> ::menu();     //二叉树操作菜单
    cout<<"请输入执行序号:";
    cin>>x;
    while(x!=0)
    {
        switch(x)
        {   //数据文件创建二叉树
            case 1:
                if(root!=NULL)
                {
                    T.destory(root);
                }
                cout<<"请输入打开的文件名:";
                cin>>fileName;
                if(T.ReadFileToArray(fileName,strLine,nLen))
                {
                    if(T.CreatBiTreeFromFile(root,strLine,nLen,nRow))
                    {
                        cout<<"数据处理完毕!"<<endl;
                    }
                }
            break;
            //控制台交互输入创建二叉树
            case 2:
                if(root!=NULL)
                {
                    T.destory(root);
                }
                T.createBiTree(root);
            break;
            //3先序、中序、后序遍历输出
            case 3:
                cout<<"先序序列为:";
                T.perOrderTraverse(root);
                cout<<endl;
                cout<<"中序序列为:";
                T.inOrderTraverse(root);
                cout<<endl;
                cout<<"后序序列为:";
                T.postOrderTraverse(root);
                cout<<endl;
            break;
            //4中序次序输出二叉树中各结点的值及其所对应的层次数
            case 4:
                T.outOrderTraverse(root,level);
            break;
            //5求二叉树的高度
            case 5:
                cout<<"此树高度为:"<<T.BiTreeDepth(root)<<endl;
            break;
            //6求二叉树的结点数
            case 6:
                T.GetNodeNumber(root,nNodeNum);
                cout<<"共有"<<nNodeNum<<"个节点"<<endl;
            break;
            //7求二叉树的叶子结点数
            case 7:
                T.leafNodeNum(root,leafNodeNum);
                cout<<"共有"<<leafNodeNum<<"个叶子节点"<<endl;
            break;
            //8求二叉树的度为2的结点数
            case 8:
                T.TwoBranchNodeNum(root,TwoBranchNodeNum);
                cout<<"共有"<<TwoBranchNodeNum<<"个度为2的节点"<<endl;
            break;
            //9键盘输入一个元素x,求其父节点、兄弟结点、孩子结点的值
            case 9:
                cout<<"请输入要查询x的值:";
                cin>>y;
                T.GetFatherBrotherChildNode(root,y);
            break;
            //10键盘输入一个元素x,求其在树中的层次
            case 10:
                cout<<"请输入要查询x的值:";
                cin>>y;
                T.GetNodeLevel(root,y,level,flag);
            break;
            //11将按顺序方式存储在数组中的二叉树转换为二叉链表形式
            case 11:
                if(root!=NULL)
                {
                    T.destory(root);
                }
                cout<<"请依次输入字符(输入字符\\结束):"<<endl;
                for(int t=1;t<100;t++)
                {
                    cin>>y;
                    if(y=='\\')     //注意转义字符的使用
                    break;
                    A[t]=y;
                    num++;
                }
                T.ArrayToBiTree(root,A,i,num);
            break;
            //12交换二叉树中每个结点的左右孩子指针的值
            case 12:
                T.ExchangeTree(root);
                cout<<"交换完成!";
            break;
            //13复制一棵二叉树T到T1(选做题)
            case 13:
           //     T.GetNodeNumber(root,nNodeNum);
                T.BiTreeToArray(root,A,i,count);
                T1.ArrayToBiTree(root1,A,i,count);
                cout<<"复制完成!"<<endl;
                cout<<"先序序列为:";
                T1.perOrderTraverse(root1);
                cout<<endl;
                cout<<"中序序列为:";
                T1.inOrderTraverse(root1);
                cout<<endl;
                cout<<"后序序列为:";
                T1.postOrderTraverse(root1);
                cout<<endl;
            break;
            case 14:
                T.PrintRoute(root,A,pathLen);
            break;
            case 15:
                count=i=1;
                T.BiTreeToArray(root,B,i,count);
                T.LevelTraverse(root,B,count);
                count=i=1;
            break;
            case 16:
                cout<<"请输入树中节点的元素值:";
                cin>>y;
                cout<<"请输入树中另一个节点的元素值:";
                cin>>z;
                T.SearchBiTree(root,s1,y);
                T.SearchBiTree(root,s2,z);
                while((s1.top()!=s2.top())||s1.getLen()!=s2.getLen())
                {
                    if(s1.getLen()>s2.getLen())
                    {
                        s1.pop(c);
                    }
                    else if(s1.getLen()<s2.getLen())
                    {
                        s2.pop(c);
                    }
                    else{
                        if(s1.top()==s2.top())
                        {
                                break;
                        }
                        else{
                            s1.pop(c);
                            s2.pop(c);
                        }
                    }
                }
                if(s1.top()->data==s2.top()->data&&s1.top()->data==y)
                {
                    s1.pop(c);
                    cout<<"两个节点的共同祖先为:"<<s1.top()->data<<endl;
                }
                else if(s1.top()->data==s2.top()->data&&s1.top()->data==z)
                {
                    s1.pop(c);
                    cout<<"两个节点的共同祖先为:"<<s1.top()->data<<endl;
                }
                else{
                    cout<<"两个节点的共同祖先为:"<<s1.top()->data<<endl;
                }
            break;
            case 17:
                maxLen=T.BiTreeDepth(root);
                T.PrintMaxLenPath(root,maxLen);
            break;
            case 18:
                T.PrintAllPath(root);
            break;
        }
        system("PAUSE");
        system("CLS");
        BiTree <char> ::menu();
        cout<<"请输入执行序号:";
        cin>>x;
    }
    //这里需要添加销毁二叉树的相关操作
    if(root!=NULL)
        T.destory(root);
    T1.destory(root1);
    return 0;
}

五、运行和测试

六、实验截图

发布了46 篇原创文章 · 获赞 48 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_39559641/article/details/89069634