二叉树(三十五)

        上节博客我们介绍了通用树到二叉树的转换,今天我们就来看看二叉树的实现。我们先来看看它的组成结构,如下

图片.png

        设计要点:

            1、BTree 为二叉树结构,每个结点最多只有两个后继结点;

            2、BTreeNode 只包含 4 个固定的公有成员(左树、右树、构造函数、工厂模式创建新结点函数);

            3、实现树结构的所有操作(增、删、查等);

        下来我们来看看 BTreeNode 和 BTree 的设计与实现,如下

图片.png

图片.png

        下来我们来看看 BTree(二叉树结构)的实现框架,如下图所示

图片.png

        我们来看看具体的 BTree 和 BTreeNode 的源码实现


BTreeNode.h 源码

#ifndef BTREENODE_H
#define BTREENODE_H

#include "Tree.h"

namespace DTLib
{

template < typename T >
class BTreeNode : public TreeNode<T>
{
public:
    BTreeNode<T>* left;
    BTreeNode<T>* right;

    BTreeNode()
    {
        left = NULL;
        right = NULL;
    }

    static BTreeNode<T>* NewNode()
    {
        BTreeNode<T>* ret = new BTreeNode<T>();

        if( ret != NULL )
        {
            ret->m_flag = true;
        }

        return ret;
    }
};

}

#endif // BTREENODE_H


BTree.h 源码

#ifndef BTREE_H
#define BTREE_H

#include "Tree.h"
#include "BTreeNode.h"

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
public:
    bool insert(TreeNode<T>* node)
    {
        bool ret = true;
        
        return ret;
    }

    virtual bool insert(TreeNode<T>* node, BTNodePos pos)
    {
        bool ret = true;

        return ret;
    }

    bool insert(const T& value, TreeNode<T>* parent)
    {
        bool ret = true;

        return ret;
    }

    SharedPointer< Tree<T> > remove(const T& value)
    {
        return NULL;
    }

    SharedPointer< Tree<T> > remove(TreeNode<T>* node)
    {
        return NULL;
    }

    BTreeNode<T>* find(const T& value) const
    {
        return NULL;
    }

    BTreeNode<T>* find(TreeNode<T>* node) const
    {
        return NULL;
    }

    BTreeNode<T>* root() const
    {
        return dynamic_cast<BTreeNode<T>*>(this->m_root);
    }

    int degree() const
    {
        return 0;
    }

    int count() const
    {
        return 0;
    }

    int height() const
    {
        return 0;
    }

    void clear()
    {
        this->m_root = NULL;
    }

    ~BTree()
    {
        clear();
    }
};

}

#endif // BTREE_H

        我们看到它的框架和我们之前实现的通用树差不多,下来我们来一一的实现它的所有操作

        1、查找操作

            a> 基于数据元素值的查找:BTreeNode<T>* find(const T& value) const;b> 基于结点的查找:BTreeNode<T>* find(TreeNode<T>* node) const

        a> 基于数据元素值的查找,定义功能:find(node, value)。在 node 为根结点的二叉树中查找 value 所在的结点,如下

图片.png

        b> 基于结点的查找,定义功能:find(node, obj)。在 node 为根结点的二叉树中查找是否存在 obj 结点,如下

图片.png

        具体源码实现如下

#ifndef BTREE_H
#define BTREE_H

#include "Tree.h"
#include "BTreeNode.h"
#include "Exception.h"
#include "LinkQueue.h"
#include "DynamicArray.h"

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    virtual BTreeNode<T>* find(BTreeNode<T>* node, const T& value) const    
    {
        BTreeNode<T>* ret = NULL;

        if( node != NULL )
        {
            if( node->value == value )
            {
                ret = node;
            }
            else
            {
                if( ret == NULL )
                {
                    ret = find(node->left, value);
                }

                if( ret == NULL )
                {
                    ret = find(node->right, value);
                }
            }
        }

        return ret;
    }

    virtual BTreeNode<T>* find(BTreeNode<T>* node, BTreeNode<T>* obj) const
    {
        BTreeNode<T>* ret = NULL;

        if( node != NULL )
        {
            if( node == obj )
            {
                ret = node;
            }
            else
            {
                if( ret == NULL )
                {
                    ret = find(node->left, obj);
                }

                if( ret == NULL )
                {
                    ret = find(node->right, obj);
                }
            }
        }

        return ret;
    }
public:
  BTreeNode<T>* find(const T& value) const    
  {
        return find(root(), value);
    }

    BTreeNode<T>* find(TreeNode<T>* node) const
    {
        return find(root(), dynamic_cast<BTreeNode<T>*>(node));
    }

    BTreeNode<T>* root() const
    {
        return dynamic_cast<BTreeNode<T>*>(this->m_root);
    }
};

}

#endif // BTREE_H

        2、插入操作

        我们在进行插入操作的时候不是二叉树的任意结点都能插入,必须得指明插入新结点的位置,是左子树还是右子树,不指明便是从左向右的进行插入。因此我们得定义一个枚举,用来表示二叉树结点的位置。插入操作也分为两种:a> 插入新结点:bool insert(TreeNode<T>* node); bool insert(TreeNode<T>* node, BTNodePos pos); b> 插入数据元素:bool insert(const T& value, TreeNode<T>* parent); bool insert(const T& value, TreeNode<T>* parent, BTNodePos pos)。

        新结点的插入如图所示

图片.png

        a> 指定位置的结点插入,如下图所示

图片.png

        插入新结点,如下图所示

图片.png

        b> 插入数据元素

图片.png

        我们来看看源码具体是怎么实现的

namespace DTLib
{

enum BTTraversal
{
    PreOrder,
    Inorder,
    PostOrder,
    LeverOrder
};

template < typename T >
class BTree : public Tree<T>
{
protected:
    virtual bool insert(BTreeNode<T>* n, BTreeNode<T>* np, BTNodePos pos)
    {
        bool ret = true;

        if( pos == ANY )
        {
            if( np->left == NULL )
            {
                np->left = n;
            }
            else if( np->right == NULL )
            {
                np->right = n;
            }
            else
            {
                ret = false;
            }
        }
        else if( pos == LEFT )
        {
            if( np->left == NULL )
            {
                np->left = n;
            }
            else
            {
                ret = false;
            }
        }
        else if( pos == RIGHT )
        {
            if( np->right == NULL )
            {
                np->right = n;
            }
            else
            {
                ret = false;
            }
        }
        else
        {
            ret = false;
        }

        return ret;
    }
public:    
    bool insert(TreeNode<T>* node)
    {
        return insert(node, ANY);
    }

    virtual bool insert(TreeNode<T>* node, BTNodePos pos)
    {
        bool ret = true;

        if( node != NULL )
        {
            if( this->m_root == NULL )
            {
                node->parent = NULL;
                this->m_root = node;
            }
            else
            {
                BTreeNode<T>* np = find(node->parent);

                if( np != NULL )
                {
                    ret = insert(dynamic_cast<BTreeNode<T>*>(node), np, pos);
                }
                else
                {
                    THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree ndoe ....");
                }
            }
        }
        else
        {
            THROW_EXCEPTION(InvalidParameterException, "Parameter node can not be NULL ...");
        }

        return ret;
    }

    bool insert(const T& value, TreeNode<T>* parent)
    {
        return insert(value, parent, ANY);
    }

    virtual bool insert(const T& value, TreeNode<T>* parent, BTNodePos pos)
    {
        bool ret = true;
        BTreeNode<T>* node = BTreeNode<T>::NewNode();

        if( node == NULL )
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new node ...");
        }
        else
        {
            node->value = value;
            node->parent = parent;

            ret = insert(node, pos);

            if( !ret )
            {
                delete node;
            }
        }

        return ret;
    }
};

}

        3、结点删除与清除

            a> 基于数据元素值的删除:SharedPointer< Tree<T> > remove(const T& value); b> 基于结点的删除:SharedPointer< Tree<T> > remove(TreeNode<T>* node)。

        二叉树中结点的删除如下图所示

图片.png

        删除操作功能的定义:virtual void remove(BTreeNode<T>* node, BTree<T>*& ret); 将在 node 为根结点的子树从原来的二叉树中删除,ret 作为子树返回(ret 指向堆空间中的二叉树对象),下来我们来看看删除功能函数的实现流程,如下图所示

图片.png

        清除操作的定义:void clear(),将二叉树中的所有结点清除(释放堆中的结点),如下所示

图片.png

        功能定义:free(node),清除 node 为根结点的二叉树,释放二叉树中的每一个结点,如下

图片.png

        我们来看看具体源码的实现

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    virtual void remove(BTreeNode<T>* node, BTree<T>*& ret)    
    {
        ret = new BTree<T>();

        if( ret == NULL )
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memroy to create new tree ...");
        }
        else
        {
            if( root() == node )
            {
                this->m_root = NULL;
            }
            else
            {
                BTreeNode<T>* parent = dynamic_cast<BTreeNode<T>*>(node->parent);

                if( parent->left == node )
                {
                    parent->left = NULL;
                }
                else if( parent->right == node )
                {
                    parent->right = NULL;
                }

                node->parent = NULL;
            }

            ret->m_root = node;
        }
    }
    
    virtual void free(BTreeNode<T>* node)    
    {
            if( node != NULL )
            {
                free(node->left);
                free(node->right);
    
                if( node->flag() )
                {
                    delete node;
                }
            }
        }
public:    
    SharedPointer< Tree<T> > remove(const T& value)
    {
        BTree<T>* ret = NULL;
        BTreeNode<T>* node = find(value);

        if( node == NULL )
        {
            THROW_EXCEPTION(InvalidParameterException, "Can not find the tree node via value ...");
        }
        else
        {
            remove(node, ret);
            m_queue.clear();
        }

        return ret;
    }

    SharedPointer< Tree<T> > remove(TreeNode<T>* node)
    {
        BTree<T>* ret = NULL;

        node = find(node);

        if( node == NULL )
        {
            THROW_EXCEPTION(InvalidParameterException, "Parament node is invalid ...");
        }
        else
        {
            remove(dynamic_cast<BTreeNode<T>*>(node), ret);
            m_queue.clear();
        }

        return ret;
    }
    
    void clear()    
    {
            free(root());

            this->m_root = NULL;
        }
};

}

        4、属性操作

        在二叉树中,它的属性操作有三种:a> 结点数目;b> 高度;c> 度数。

        a> 二叉树中结点的数目,定义功能:count(node)。在 node 为根结点的二叉树中统计结点数目,如下图所示

图片.png

        b> 二叉树的高度,定义功能:height(node)。获取 node 为根结点的二叉树的高度,如下图所示

图片.png

        c> 二叉树的度数,定义功能:degree(node)。获取 node 为根结点的二叉树的度数,如下图所示

图片.png

        下来我们来看看具体源码是怎么实现的

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    int count(BTreeNode<T>* node) const    
    {
        return (node != NULL) ? (count(node->left) + count(node->right) + 1) : 0;
    }

    int height(BTreeNode<T>* node) const
    {
        int ret = 0;

        if( node != NULL )
        {
            int lh = height(node->left);
            int rh = height(node->right);

            ret = ((lh > rh) ? lh : rh) + 1;
        }

        return ret;
    }

    int degree(BTreeNode<T>* node) const
    {
        int ret = 0;

        if( node != NULL )
        {
            BTreeNode<T>* child[] = { node->left, node->right };

            ret = !!node->left + !!node->right;

            for(int i=0; (i<2) && (ret<2); i++)
            {
                int d = degree(child[i]);

                if( ret < d )
                {
                    ret = d;
                }
            }
        }

        return ret;
    }
public:    
    int degree() const    
    {
        return degree(root());
    }

    int count() const
    {
        return count(root());
    }

    int height() const
    {
        return height(root());
    }
};

}

        5、层次遍历

        二叉树的遍历是指从根结点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问一次,且仅被访问一次。设计思路(游标),提供一组遍历相关的函数,按层次访问二叉树中的数据元素,如下

图片.png

        层次遍历算法:a> 原料:class LinkQueue<T>; b> 游标:LinkQueue<T>::front();

        思想:a> begin() --> 将根结点压入队列中;

                  b> current() --> 访问队头元素指向的数据元素;

                  c> next() --> 队头元素弹出,将队头元素的盖子压入队列中(核心);

                  d> end() --> 判断队列是否为空。

        层次遍历算法示例如下

图片.png

        具体源码实现如下

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    LinkQueue<BTreeNode<T>*> m_queue;
public:    
    bool begin()    
    {
        bool ret = (root() != NULL);

        if( ret )
        {
            m_queue.clear();
            m_queue.add(root());
        }

        return ret;
    }

    bool end()
    {
        return (m_queue.length() == 0);
    }

    bool next()
    {
        bool ret = (m_queue.length() > 0);

        if( ret )
        {
            BTreeNode<T>* node = m_queue.front();

            m_queue.remove();

            if( node->left != NULL )
            {
                m_queue.add(node->left);
            }

            if( node->right != NULL )
            {
                m_queue.add(node->right);
            }
        }

        return ret;
    }

    T current()
    {
        if( !end() )
        {
            return m_queue.front()->value;
        }
        else
        {
            THROW_EXCEPTION(InvalidParameterException, "No value at current position ...");
        }
    }
};

}

        6、典型遍历方式

               典型的遍历方式:a> 先序遍历;b> 中序遍历;c> 后序遍历。

        a> 先序遍历:二叉树为空,则直接返回;若不为空:1、访问根结点中的数据元素,2、先序遍历左子树,3、先序遍历右子树。如下图所示

图片.png

        先序遍历功能定义如下

图片.png

        b> 中序遍历:二叉树为空,则直接返回;若不为空:1、中序遍历左子树,2、访问根结点中的数据元素,3、中序遍历右子树。如下图所示

图片.png

        中序遍历功能定义如下

图片.png

        c> 后序遍历:二叉树为空,则直接返回;若不为空:1、后序遍历左子树,2、后序遍历右子树,3、访问根结点中的数据元素。如下图所示

图片.png

        后序遍历功能定义如下

图片.png

        我们可以将二叉树的典型遍历算法集成到 BTree 中,设计要点:不能与层次遍历函数冲突,必须设计新的函数接口;算法执行完成后,能够方便的获得遍历结果;遍历结果能够反映结点访问的先后次序。

        函数接口设计:SharedPointer< Array<T> > traversal(BTTraversal order);根据参数 order 选择执行遍历算法(先序、中序、后序),返回值为堆中的数组对象(生命周期由智能指针管理),数组元素的次序反映遍历的先后次序。典型的遍历示例如下所示

图片.png

        下来我们来看看具体的源码实现

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    void perOrderTraversal(BTreeNode<T>* node, LinkQueue<BTreeNode<T>*>& queue)    
    {
        if( node != NULL )
        {
            queue.add(node);
            perOrderTraversal(node->left, queue);
            perOrderTraversal(node->right, queue);
        }
    }

    void inOrderTraversal(BTreeNode<T>* node, LinkQueue<BTreeNode<T>*>& queue)
    {
        if( node != NULL )
        {
            inOrderTraversal(node->left, queue);
            queue.add(node);
            inOrderTraversal(node->right, queue);
        }
    }

    void postOrderTraversal(BTreeNode<T>* node, LinkQueue<BTreeNode<T>*>& queue)
    {
        if( node != NULL )
        {
            postOrderTraversal(node->left, queue);
            postOrderTraversal(node->right, queue);
            queue.add(node);
        }
    }
    
    void traversal(BTTraversal order, LinkQueue<BTreeNode<T>*>& queue)    
    {
        switch (order)
        {
            case PreOrder:
                perOrderTraversal(root(), queue);
                break;
            case Inorder:
                inOrderTraversal(root(), queue);
                break;
            case PostOrder:
                postOrderTraversal(root(), queue);
                break;
            default:
                THROW_EXCEPTION(InvalidParameterException, "Parameter order is invalid ...");
                break;
        }
    }
public:    
    SharedPointer< Array<T> > traversal(BTTraversal order)    
    {
        DynamicArray<T>* ret = NULL;
        LinkQueue<BTreeNode<T>*> queue;

        traversal(order, queue);

        ret = new DynamicArray<T>(queue.length());

        if( ret != NULL )
        {
            for(int i=0; i<ret->length(); i++, queue.remove())
            {
                ret->set(i, queue.front()->value);
            }
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create return tree ...");
        }

        return ret;
    }
};

}

        7、比较与相加

        要进行比较与相加,首先必须得进行克隆。我们先来看看二叉树的克隆:SharedPointer< BTree<T> > clone() const;克隆当前树的一份拷贝,返回值为堆空间中的一颗新二叉树(与当前树相等)。定义功能:clone(node),拷贝 node 为根结点的二叉树(数据元素在对应位置相等),如下图所示

图片.png

        二叉树比较操作的定义,判断两颗二叉树中的数据元素是否对应相等:bool operator == (const BTree<T>& btree);bool operator != (const BTree<T>& btree)。如下

图片.png

        二叉树的比较,定义功能:equal(lh, rh)。判断 lh 为根结点的二叉树与 rh 为根结点的二叉树是否相等,如下

图片.png

        二叉树的相加操作:SharedPointer< BTree<T> > add(const BTree<T>& btree) const;将当前二叉树与参数 btree 中的数据元素在对应位置处相加,返回值(相加的结果)为堆空间中的一颗新二叉树。如下

图片.png

        二叉树的加法,定义功能:add(lh, rh)。将 lh 为根结点的二叉树与 rh 为根结点的二叉树相加,如下

图片.png

        具体源码实现如下

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    BTreeNode<T>* clone(BTreeNode<T>* node) const    
    {
        BTreeNode<T>* ret = NULL;

        if( node != NULL )
        {
            ret = BTreeNode<T>::NewNode();

            if( ret != NULL )
            {
                ret->value = node->value;

                ret->left = clone(node->left);
                ret->right = clone(node->right);

                if( ret->left != NULL )
                {
                    ret->left->parent = ret;
                }

                if( ret->right != NULL )
                {
                    ret->right->parent = ret;
                }
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "No memory to clone old tree ...");
            }
        }

        return ret;
    }

    bool equal(BTreeNode<T>* rh, BTreeNode<T>* lh) const
    {
        if( lh == rh )
        {
            return true;
        }
        else if( (lh != NULL) && (rh != NULL) )
        {
            return (lh->value == rh->value) && equal(lh->left, rh->left) && equal(lh->right, rh->right);
        }
        else
        {
            return false;
        }
    }

    BTreeNode<T>* add(BTreeNode<T>* lh, BTreeNode<T>* rh) const
    {
        BTreeNode<T>* ret = NULL;

        if( (lh == NULL) && (rh != NULL) )
        {
            ret = clone(rh);
        }
        else if( (lh != NULL) && (rh == NULL) )
        {
            ret = clone(lh);
        }
        else if( (lh != NULL) && (rh != NULL) )
        {
            ret = BTreeNode<T>::NewNode();

            if( ret != NULL )
            {
                ret->value = lh->value + rh->value;

                ret->left = add(lh->left, rh->left);
                ret->right = add(lh->right, rh->right);

                if( ret->left != NULL )
                {
                    ret->left->parent = ret;
                }

                if( ret->right != NULL )
                {
                    ret->right->parent = ret;
                }
            }
            else
            {
                THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new node ...");
            }
        }

        return ret;
    }
public:    
    SharedPointer< BTree<T> > clone() const    
    {
        BTree<T>* ret = new BTree<T>();

        if( ret != NULL )
        {
            ret->m_root = clone(root());
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new btree ...");
        }

        return ret;
    }

    bool operator == (const BTree<T>& btree)
    {
        return equal(root(), btree.root());
    }

    bool operator != (const BTree<T>& btree)
    {
        return !(*this == btree);
    }

    SharedPointer< BTree<T> > add(const BTree<T>& btree) const
    {
        BTree<T>* ret = new BTree<T>();

        if( ret != NULL )
        {
            ret->m_root = add(root(), btree.root());
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create new tree ...");
        }

        return ret;
    }
};

}

        8、二叉树的线索优化实现

        什么叫线索优化?将二叉树转换为双向链表的过程(非线性 --> 线性);能够反映某种二叉树的遍历次序(结点的先后访问次序),利用结点的 right 指针指向遍历中的后继结点,利用结点的 left 指针指向遍历中的前驱节点。

        如何对二叉树进行线索化呢?过程如下

图片.png

        二叉树的线索化,如下

图片.png

        层次遍历算法如下:

            1、将根结点压入队列中;

            2、访问队头元素指向的二叉树结点;

            3、队头元素弹出,将队头元素的孩子压入队列中;

            4、判断队列是否为空(非空:转 2,空:结束)。

        层次遍历算法示例如下

图片.png

图片.png

        函数接口设计:BTreeNode<T>* thread(BTTraversal order);根据参数 order 选择线索化的次序(先序、中序、后序、层次),返回值线索化之后指向链表首结点的指针,线索化执行结束后对应的二叉树变为空树。线索化流程如下所示

图片.png

        队列中结点的连接算法如下所示 [connect(queue)]

图片.png

        具体源码实现如下

namespace DTLib
{

template < typename T >
class BTree : public Tree<T>
{
protected:
    void levelOrderTraversal(BTreeNode<T>* node, LinkQueue<BTreeNode<T>*>& queue)    
    {
        if( node != NULL )
        {
            LinkQueue<BTreeNode<T>*> tmp;

            tmp.add(root());

            while( tmp.length() > 0 )
            {
                BTreeNode<T>* n = tmp.front();

                if( n->left != NULL )
                {
                    tmp.add(n->left);
                }

                if( n->right != NULL )
                {
                    tmp.add(n->right);
                }

                tmp.remove();
                queue.add(n);
            }
        }
    }
    
    void traversal(BTTraversal order, LinkQueue<BTreeNode<T>*>& queue)    
    {
        switch (order)
        {
            case PreOrder:
                perOrderTraversal(root(), queue);
                break;
            case Inorder:
                inOrderTraversal(root(), queue);
                break;
            case PostOrder:
                postOrderTraversal(root(), queue);
                break;
            case LeverOrder:
                levelOrderTraversal(root(), queue);
                break;
            default:
                THROW_EXCEPTION(InvalidParameterException, "Parameter order is invalid ...");
                break;
        }
    }

    BTreeNode<T>* connect(LinkQueue<BTreeNode<T>*>& queue)
    {
        BTreeNode<T>* ret = NULL;

        if( queue.length() > 0 )
        {
            ret = queue.front();

            BTreeNode<T>* slider = queue.front();

            queue.remove();

            slider->left = NULL;

            while( queue.length() > 0 )
            {
                slider->right = queue.front();
                queue.front()->left = slider;
                slider = queue.front();
                queue.remove();
            }

            slider->right = NULL;
        }

        return ret;
    }
public:    
    BTreeNode<T>* thread(BTTraversal order)    
    {
        BTreeNode<T>* ret = NULL;
        LinkQueue<BTreeNode<T>*> queue;

        traversal(order, queue);

        ret = connect(queue);

        this->m_root = NULL;

        m_queue.clear();

        return ret;
    }
};

}

        通过对二叉树的学习,总结如下:1、二叉树的插入操作必须指明其插入的位置,正确处理指向父结点的指针;2、插入数据元素时需要从堆空间中创建结点,当数据元素插入失败时需要释放结点空间;3、删除操作将目标结点所代表的子树移除,必须完善处理父结点和子结点的关系;4、清除操作作用于销毁树中的每个结点,销毁结点时判断是否释放对应的内存空间(工厂模式);5、二叉树的典型遍历都是以递归方式执行的,BTree 以不同的函数接口支持典型遍历;6、层次遍历与典型遍历互不冲突,遍历结果能够反映树结点访问的先后次序;7、比较操作判断两棵二叉树中的数据元素是否对应相等,克隆操作将当前二叉树在堆空间中进行复制;8、相加操作将两颗二叉树中的数据元素在对应位置处相加,结果保存在堆空间的一颗二叉树中。

猜你喜欢

转载自blog.51cto.com/12810168/2310464