数据结构-二叉树(2)链表法和广义表法表示二叉树

数组表示法用于完全二叉树的存储表示非常有效,但表示一般二叉树,尤其是形态剧烈变化的二叉树,存储空间的利用很不理想

使用二叉链表表示二叉树:

#include <iostream>
using namespace std;

template <class T>
struct BinTreeNode{
    T data;
    BinTreeNode<T> *leftChild,*rightChild;
    BinTreeNode():leftChild(NULL),rightChild(NULL){}
    BinTreeNode(T x,BinTreeNode<T> *l=NULL,BinTreeNode<T> *r=NULL):data(x),leftChild(l),rightChild(r){};
};

template <class T>
class BinaryTree{
public:
    BinaryTree():root(NULL){}
    BinaryTree(T value):RefValue(value),root(NULL){}
    BinaryTree(const BinaryTree<T>& s){root=Copy(s.root);}  //复制构造函数
    ~BinaryTree(){destroy(root);}
    bool IsEmpty(){return(root==NULL);}
    BinTreeNode<T> *Parent(BinTreeNode<T> *current){        //返回父结点
        return(root==NULL||root==current)?NULL:Parent(root,current);
    }
    BinTreeNode<T> *LeftChild(BinTreeNode<T> *current){    //返回左子女
        return(current!=NULL)?current->leftChild:NULL;
    }
    BinTreeNode<T> *RightChild(BinTreeNode<T> *current){    //返回右子女
        return(current!=NULL)?current->rightChild:NULL;
    }
    int Height(){return Height(root);}     //返回树高度
    int Size(){return Size(root);}       //返回结点数
    BinTreeNode<T> *getRoot()const{return root;} //取根
    void preOrder(void (*visit)(BinTreeNode<T> *p)){preOrder(root,visit);}   //对根结点前序遍历
    void InOrder(void (*visit)(BinTreeNode<T> *p)){InOrder(root,visit);}   //对根结点中序遍历
    void postOrder(void (*visit)(BinTreeNode<T> *p)){postOrder(root,visit);}   //对根结点后序遍历
    void levelOrder(void (*visit)(BinTreeNode<T> *p));   //层次序遍历
    int Insert(const T& item);             //插入新元素
    BinTreeNode<T> *Find(T& item)const;   //搜索
protected:
    BinTreeNode<T> *root;  //二叉树根指针
    T RefValue;            //数据输入停止标志,用广义表表示二叉树的时候用
    void CreateBinTree(istream& in,BinTreeNode<T> *subTree); //从文件读入建树
    bool Insert(BinTreeNode<T> *subTree,const T&x);      //插入
    void destroy(BinTreeNode<T> *subTree);              //删除
    BinTreeNode<T> *Copy(BinTreeNode<T> *orignode);      //复制
    int Height(BinTreeNode<T> *subTree)const;                 //返回树高度
    int Size(BinTreeNode<T> *subTree)const;                    //返回结点数
    BinTreeNode<T> *Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current); //从结点subTree开始搜索结点current的父结点
    BinTreeNode<T> *Find(BinTreeNode<T> *subTree,const T& x)const;   //搜寻值为x的结点
    void Traverse(BinTreeNode<T> *subTree,ostream& out);     //前序遍历输出
    void preOrder(BinTreeNode<T>* subTree,
                  void (*visit)(BinTreeNode<T> *p));   //对p结点前序遍历
    void InOrder(BinTreeNode<T>* subTree,
                 void (*visit)(BinTreeNode<T> *p));   //中序遍历
    void postOrder(BinTreeNode<T>* subTree,
                   void (*visit)(BinTreeNode<T> *p));   //后序遍历
    friend istream& operator>>(istream& in,BinaryTree<T>& Tree);
    friend ostream& operator<<(ostream& out,BinaryTree<T>& Tree);
    friend bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t);
    bool equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const;
};

template <class T>
void BinaryTree<T>::destroy(BinTreeNode<T> *subTree){
    //私有函数,若指针subTree不为空,则删除根为subTree的子树
    if(subTree!=NULL){
        destroy(subTree->leftChild);
        destroy(subTree->rightChild);
        delete subTree;
    }
}

template <class T>
BinTreeNode<T> *BinaryTree<T>::Parent(BinTreeNode<T> *subTree,BinTreeNode<T> *current){
    //私有函数,从结点subTree开始搜索结点current的父结点,返回父结点地址或者NULL
    if(subTree==NULL) return NULL;
    if(subTree->leftChild==current || subTree->rightChild==current) return subTree;
    BinTreeNode<T> *p;
    if((p=Parent(subTree->leftChild,current))!=NULL) return p;      //使用p=Parent(subTree->leftChild,current)递归在左子树中搜索,p==NULL则说明搜索失败
    else return Parent(subTree->rightChild,current);
}

template <class T>
void BinaryTree<T>::Traverse(BinTreeNode<T> *subTree,ostream& out){
    //私有函数,搜索并前序输出根为subTree的二叉树
    if(subTree!=NULL){
        out<<subTree->data<<'';
        Traverse(subTree->leftChild,out);  //递归搜索并输出subTree的左子树
        Traverse(subTree->rightChild,out); //递归搜索并输出subTree的右子树
    }
}

template <class T>
istream& operator>>(istream& in,BinaryTree<T>& Tree){
    //重载操作,输入并建立一颗二叉树Tree,in是输入流对象
    Tree.CreateBinTree(in,Tree.root);    //此处友元函数不能直接访问类的成员函数
    return in;
}

template <class T>
ostream& operator<<(ostream& out,BinaryTree<T>& Tree){
    //重载操作,输出一颗二叉树Tree,out是输出流对象
    out<<"二叉树的前序遍历\n";
    Tree.Traverse(Tree.root,out);         //从根开始输出
    out<<endl;
    return out;
}

template <class T>
bool operator==(const BinaryTree<T>& s,const BinaryTree<T>& t){
    //判断两棵二叉树的等价性,它需要是BinaryTree类的友元函数
    return s.equal(s.root,t.root);   //此处s是const对象,equal应该是const方法
}

template <class T>
void BinaryTree<T>::preOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    if(subTree!=NULL){
        visit(subTree);
        preOrder(subTree->leftChild,visit);
        preOrder(subTree->rightChild,visit);
    }
}

template <class T>
void BinaryTree<T>::InOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    //递归函数,此算法按照中序次序遍历以subTree为根的子树
    if(subTree!=NULL){
        InOrder(subTree->leftChild,visit);
        visit(subTree);
        InOrder(subTree->rightChild,visit);
    }
}

template <class T>
void BinaryTree<T>::postOrder(BinTreeNode<T> *subTree, void (*visit)(BinTreeNode<T> *)) {
    if(subTree!=NULL){
        postOrder(subTree->leftChild,visit);
        postOrder(subTree->rightChild,visit);
        visit(subTree);
    }
}

template <class T>
int BinaryTree<T>::Size(BinTreeNode<T> *subTree)const{
    //私有函数,介绍以subTree为根的二叉树的结点个数
    if(subTree==NULL) return 0;
    else return 1+Size(subTree->leftChild)+Size(subTree->rightChild);
}

template <class T>
int BinaryTree<T>::Height(BinTreeNode<T> *subTree)const{
    //私有函数,计算以subTree为根的二叉树的深度
    if(subTree==NULL) return 0;
    else{
        int i=Height(subTree->leftChild);
        int j=Height(subTree->rightChild);
        return(i<j)?j+1:i+1;
    }
}

template <class T>
BinTreeNode<T> *BinaryTree<T>::Copy(BinTreeNode<T> *orignode){
    //私有函数,这个函数返回一个指针,给出一个以orignode为根的二叉树的副本
    if(orignode==NULL) return NULL;
    BinTreeNode<T> *temp=new BinTreeNode<T>;
    temp->data=orignode->data;
    temp->leftChild=Copy(orignode->leftChild);   //此处注意不能直接=,因为需要建立新结点再赋值
    temp->rightChild=Copy(orignode->rightChild);
    return temp;
}

template <class T>
bool BinaryTree<T>::equal(BinTreeNode<T> *a,BinTreeNode<T> *b)const{
    //如果a和b的子树不同,则函数返回false,否则函数返回true,它需要是BinTreeNode类的友元函数
    if(a==NULL && b==NULL) return true;
    if(a!=NULL && b!=NULL && a->data==b->data && equal(a->leftChild,b->leftChild) && equal(a->rightChild,b->rightChild)) return true;
    else return false;
}

template <class T>
void BinaryTree<T>::CreateBinTree(istream& in,BinTreeNode<T> *subTree){
    //私有函数,以前序遍历方式递归建立二叉树
    T item;
    if(!in.eof()){      //读不到输入流时in.eof()为真
        in>>item;
        subTree=new BinTreeNode<T>(item);
        if(subTree==NULL){
            cerr<<"分配存储错误!"<<endl;
            exit(1);
        }
        CreateBinTree(in,subTree->leftChild);
        CreateBinTree(in,subTree->rightChild);
    }
    else subTree=NULL;
}

二叉链表找到父结点很困难,可以使用三叉链表

输入输出二叉树时,可以输入一个广义表形式的二叉树,此时需要用栈保存字符。栈的最大深度==二叉树的高度==广义表表示中圆括号嵌套的最大层数加1(根结点)

template <class T>
void CreateBinTree(istream& in,BinTreeNode<char>* &BT){
    //从输入流in输入二叉树的广义表表示建立对应的二叉链表,依次从保存广义表的字符串ls中输入字符
    Stack<BinTreeNode<char> *> s;
    BT=NULL;    //置空二叉树表
    BinTreeNode<char> *p,*t;
    int k;  //用k作为处理左右子树标志
    char ch;
    in>>ch;
    while(ch!=RefValue){         //逐个字符处理
        switch(ch){
            case '(':s.Push(p);k=1;break;      //输入若是左扩号,则表明子表的开始,将根结点入栈,K置为1
            case ')':s.Pop(t);break;           //输入若是右括号,则表明子表结束,将根结点出栈
            case ',':k=2;break;                //遇到的是逗号,则表示以左子女为根的子树处理完毕
            default:p=new BinTreeNode(ch);     //输入若是字母,为它建立新结点,根据k的值将其链接到父节点上
                if(BT==NULL) BT=p;
                else if(k==1){
                    s.getTop(t);
                    t->leftChild=p;    //链入*t的左子女
                }
                else{
                    s.getTop(t);
                    t->rightChild=p;   //链入*t的右子女
                }
        }
        in>>ch;
    }
}

template <class T>
void PrintBTree(BinTreeNode<T> *BT){    //以广义表的形式输出二叉树
    if(BT!=NULL){
        cout<<BT->data;
        if(BT->leftChild!=NULL||BT->rightChild!=NULL){
            cout<<'(';
            PrintBTree(BT->leftChild);
            cout<<',';
            if(BT->rightChild!=NULL)
                PrintBTree(BT->rightChild);
            cout<<')';
        }
    }
}

 

posted @ 2018-08-08 16:38  扬羽流风  阅读(3061)  评论(0编辑  收藏  举报