二叉树中的结点查找、插入

前面实现了通用树结构,介绍了树到二叉树的转换,这节实现二叉树中的结点查找、插入


目录

1、 二叉树的存储结构设计

2、二叉树中的结点查找操作 

3、二叉树中的结点插入操作


1、 二叉树的存储结构设计

        目标:完成二叉树二叉树结点的存储结构设计 

            二叉树中的结点查找、插入_第1张图片

设计要点 

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

     - BTreeNode只包含4个固定的公有成员(哪4个?) 

     - 实现树结构的所有操作(增,删,查,等) 

                            注意我们研究的是二叉树的实际工程应用,在实际工程中加个parent指针是十分必要的

BTreeNode的设计与实现 

                            二叉树中的结点查找、插入_第2张图片

template < typename T >
class BTreeNode : public TreeNode
{

public:
    BTreeNode* left;
    BTreeNode* right;

    // factory pattern

    // ...
};

                    发现 GTreeNode 和 BTreeNode 都使用了工厂模式,所以将会对之前代码重构

BTree的设计与实现 

                    二叉树中的结点查找、插入_第3张图片

                                     GTree 和 BTree 都不能对象间的赋值

BTree( 二叉树结构 ) 的实现架构

        二叉树中的结点查找、插入_第4张图片

编程实验 

二叉树结构的创建     BTree.h     BTreeNode.h

TreeNode.h (重构:将new对象的标记放在TreeNode中,在new BTreeNode 和 GTreeNode时都会做标记)

#ifndef TREENODE_H
#define TREENODE_H

#include "Object.h"

namespace DTLib
{

template < typename T >
class TreeNode : public Object
{
protected:
    bool m_flag;

    TreeNode(const TreeNode& );
    TreeNode& operator = (const TreeNode&);


    void* operator new (unsigned int size) throw()   
    {
        return Object::operator new(size);
    }
public:
    T value;
    TreeNode* parent;   

    TreeNode()
    {
        m_flag = false;

        parent = NULL;
    }

    bool flag()
    {
        return m_flag;
    }

    virtual ~TreeNode() = 0;
};

template < typename T >
TreeNode::~TreeNode()
{

}


}

#endif // TREENODE_H

BTreeNode.h

#ifndef BTREENODE_H
#define BTREENODE_H

#include "TreeNode.h"

namespace DTLib
{

template < typename T >
class BTreeNode : public TreeNode
{

public:
    BTreeNode* left;
    BTreeNode* right;

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

    static BTreeNode* NewNode()
    {
        BTreeNode* ret = new BTreeNode();

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

        return ret;
    }
};
}
#endif // BTREENODE_H

BTree.h

#ifndef BTREE_H
#define BTREE_H

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


namespace DTLib
{
template < typename T >
class BTree : public Tree
{

public:
    bool insert(TreeNode* node)
    {
        bool ret = true;

        return ret;
    }

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

        return ret;
    }

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

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

    BTreeNode* find(const T& value) const
    {
        return NULL;
    }
    BTreeNode* find(TreeNode* node) const
    {
        return NULL;
    }
    BTreeNode* root() const
    {
        return dynamic_cast*>(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

main.cpp

#include 
#include "BTree.h"

using namespace std;
using namespace DTLib;


int main()
{
   BTree bt;
   BTreeNode btn;

    return 0;
}

 

2、二叉树中的结点查找操作 

查找的方式 (和通用树查找方式完全一致)

   -基于数据元素值的查找 

                    BTreeNode<T>*  find(const T& value) const 

   -基于结点的查找 

                    BTreeNode<T>*  find(TreeNode<T>* node) const 

树中数据元素和结点的查找 

    二叉树中的结点查找、插入_第5张图片

                                                                         递归的操作

基于数据元素值的查找 

   定义功能: find(node, value

              功能:在node为根结点的二叉树中查找value所在的结点

        二叉树中的结点查找、插入_第6张图片

基于结点的查找 

   定义功能: find(node, obj

              功能:在node为根结点的二叉树中查找是否存在obj结点 

    二叉树中的结点查找、插入_第7张图片

编程实验 

基于数据元素值的查找,基于结点的查找   BTree.h

#ifndef BTREE_H
#define BTREE_H

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


namespace DTLib
{
template < typename T >
class BTree : public Tree
{
protected:
    virtual BTreeNode* find(BTreeNode* node, const T& value) const
    {
        BTreeNode* 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* find(BTreeNode* node, BTreeNode* obj) const 
    { 
        BTreeNode* ret = NULL; 
        
        if(node == obj) 
        { 
            ret = node; 
        } 
        else 
        { 
            if(node != NULL) 
            { 
                if(ret == NULL) 
                { 
                    ret = find(node->left, obj); 
                } 
                if(ret == NULL) 
                { 
                    ret = find(node->right, obj); 
                } 
            } 
        } 
        
        return ret; 
    }
public: 
    // ...

    BTreeNode* find(const T& value) const 
    { 
        return find(root(), value); 
    } 
    BTreeNode* find(TreeNode* node) const 
    { 
        return find(root(), dynamic_cast*>(node)); 
    } 
    BTreeNode* root() const 
    { 
        return dynamic_cast*>(this->m_root); 
    } 

    // ...
};

}

#endif // BTREE_H

 

3、二叉树中的结点插入操作

需要考虑的问题 

            是否能够在二叉树的任意结点处插入子结点? 

         是否需要指定新数据元素(新结点)的插入位置? 

二叉树结点的位置枚举类型 

enum BTNodePos
{
    ANY,   // 插入左右都可以
    LEFT,  // 左边插入
    RIGHT  // 右边插入
};

插入的方式 

    -插入新结点 

             bool insert(TreeNode* node)   (默认插入方式ANY)

             bool insert(TreeNode* node, BTNodePos pos) 

    -插入数据元素 

             bool insert(const T& value, TreeNode* parent) 

             bool insert(const T& value, TreeNode* parent, BTNodePos pos) 

新结点的插入

    二叉树中的结点查找、插入_第8张图片

                                                  5的左子树位置不能插入,2都不能插入

指定位置的结点插入

   ● 新结点n作为目标父结点np的孩子插入,插入位置为pos

            二叉树中的结点查找、插入_第9张图片

插入新结点 

   ● 新结点node插入node指定的父结点下pos位置

                        二叉树中的结点查找、插入_第10张图片

插入数据元素

   ● 新数据元素value作为目标父结点parent的孩子插入到pos位置

                二叉树中的结点查找、插入_第11张图片

编程实验 

二叉树的插入操作      insert

BTreeNode.h  增加枚举常量 

#ifndef BTREENODE_H
#define BTREENODE_H

#include "TreeNode.h"

namespace DTLib
{
enum BTNodePos
{
    ANY,
    LEFT,
    RIGHT
};

template < typename T >
class BTreeNode : public TreeNode
{
    // ...
};
}
#endif // BTREENODE_H

BTree.h

#ifndef BTREE_H
#define BTREE_H

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

namespace DTLib
{
template < typename T >
class BTree : public Tree
{
protected:
    // ...

    // 新结点n作为目标父结点np的孩子插入,插入位置为pos
    virtual bool insert(BTreeNode* n, BTreeNode* 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->left = n;
            }
            else
            {
                ret = false;
            }
        }
        else
        {
            ret = false;
        }

        return ret;
    }

public:
    bool insert(TreeNode* node)
    {
        return insert(node, ANY);
    }
    
    // 新结点node插入node指定的父结点下pos位置
    virtual bool insert(TreeNode* node, BTNodePos pos)
    {
        bool ret = true;

        if(node != NULL)
        {
            if(this->m_root == NULL)  // 没有根结点,node作为根结点
            {
                node->parent = NULL;
                this->m_root = node;
            }
            else
            {
                BTreeNode* np = find(node->parent);

                if(np != NULL) // node指定的父结点存在于当前树中
                {
                    ret = insert(dynamic_cast*>(node), np, pos);
                }
                else
                {
                    THROW_EXCEPTION(InvalidParameterException, "Invalid parent tree node ...");
                }
            }
        }
        else
        {
            THROW_EXCEPTION(InvalidParameterException, "Parameter node can not be NULL ...");
        }

        return ret;

    }

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

    // 新数据元素value作为目标父结点parent的孩子插入pos位置
    virtual bool insert(const T& value, TreeNode* parent, BTNodePos pos)
    {
        bool ret = true;

        BTreeNode* node = BTreeNode::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;
    }

    // ...
};
}
#endif // BTREE_H

main.cpp

#include 
#include "BTree.h"

using namespace std;
using namespace DTLib;

int main()
{
    BTree bt;
    BTreeNode* n = NULL;
    
    bt.insert(1, NULL);
    
    n = bt.find(1);
    bt.insert(2, n);
    bt.insert(3, n);
    
    
    n = bt.find(2);
    bt.insert(4, n);
    bt.insert(5, n);
    
    n = bt.find(4);
    bt.insert(8, n);
    bt.insert(9, n);
     
    n = bt.find(5);
    bt.insert(10, n);
    
    n = bt.find(3);
    bt.insert(6, n);
    bt.insert(7, n);
    
    n = bt.find(6);
    bt.insert(11, n, LEFT);
    
    int a[] = {8, 9, 10, 11, 7}; // 叶结点值
    
    for(int i=0; i<5; i++)
    {
        TreeNode* node = bt.find(a[i]);
        
        while( node ) // 遍历单链表
        {
            cout << node->value << " ";
            node = node->parent;
        }
        
        cout << endl;
        
    }

    return 0;
}

 二叉树中的结点查找、插入_第12张图片

二叉树中的结点查找、插入_第13张图片

小结 

            二叉树的插入操作需要指明插入的位置 

            插入操作必须正确处理指向父结点的指针 

            插入数据元素时需要从堆空间中创建结点 

            当数据元素插入失败时需要释放结点空间 

 

 

你可能感兴趣的:(数据结构实战开发【笔记】)