zoukankan      html  css  js  c++  java
  • 数据结构-二叉树(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<<"二叉树的前序遍历
    ";
        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<<')';
            }
        }
    }
  • 相关阅读:
    汽车租赁系统
    两种设计模式(2)==>>"单例"
    两种设计模式(1)==>>“简单工厂”
    面向对象设计的七大原则
    springboot中的mybatis是如果使用pagehelper的
    vue
    vue
    vue
    idea快捷键
    idea部署tomcat项目时,在项目里打断点不能拦截
  • 原文地址:https://www.cnblogs.com/yangyuliufeng/p/9443757.html
Copyright © 2011-2022 走看看