数据结构开发(23):二叉树中结点的查找插入删除与清除操作

Posted pylearn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构开发(23):二叉树中结点的查找插入删除与清除操作相关的知识,希望对你有一定的参考价值。

0.目录

1.二叉树中结点的查找操作

2.二叉树中结点的插入操作

3.二叉树中结点的删除操作

4.二叉树中结点的清除操作

5.小结

1.二叉树中结点的查找操作

查找的方式:

  • 基于数据元素值的查找
    1. BTreeNode<T>* find(const T& value) const
  • 基于结点的查找
    1. BTreeNode<T>* find(TreeNode<T>* node) const

树中数据元素和结点的查找:
技术分享图片

基于数据元素值的查找:

  • 定义功能:find(node, value)
    1. node 为根结点的二叉树中查找 value 所在的结点

技术分享图片

在BTree.h中实现基于数据元素值的查找:

protected:
    virtual BTreeNode<T>* find(BTreeNode<T>* node, const T& value) const
    {
        BTreeNode<T>* ret = NULL;

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

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

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

基于结点的查找:

  • 定义功能:find(node, obj)
    1. node 为根结点的二叉树中查找是否存在 obj 结点

技术分享图片

在BTree.h中实现基于结点的查找:

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

        if( node == obj )
        {
            return 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<T>* find(TreeNode<T>* node) const
    {
        return find(root(), dynamic_cast<BTreeNode<T>*>(node));
    }

2.二叉树中结点的插入操作

需要考虑的问题:

  • 是否能够在二叉树的任意结点处插入子结点?
  • 是否需要指定新数据元素 ( 新结点 ) 的插入位置?

二叉树结点的位置枚举类型:
技术分享图片

插入的方式

  • 插入新结点
    1. bool insert(TreeNode<T>* node)
    2. bool insert(TreeNode<T>* node, BTNodePos pos)
  • 插入数据元素
    1. bool insert(const T& value, TreeNode<T>* parent)
    2. bool insert(const T& value, TreeNode<T>* parent, BTNodePos pos)

新结点的插入:
技术分享图片

指定位置的结点插入:
技术分享图片

插入新结点:
技术分享图片

插入数据元素:
技术分享图片

在BTreeNode.h中实现BTNodePos枚举类型:

#ifndef BTREENODE_H
#define BTREENODE_H

#include "TreeNode.h"

namespace StLib
{

enum BTNodePos
{
    ANY,
    LEFT,
    RIGHT
};

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中实现结点的插入操作:

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 node ...");
                }
            }
        }
        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;
    }

mian.cpp测试这棵树:
技术分享图片

#include <iostream>
#include "BTree.h"

using namespace std;
using namespace StLib;

int main()
{
    BTree<int> bt;
    BTreeNode<int>* 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<int>* node = bt.find(a[i]);

        while( node )
        {
            cout << node->value << " ";
            node = node->parent;
        }

        cout << endl;
    }

    return 0;
}

运行结果为:

8 4 2 1 
9 4 2 1 
10 5 2 1 
11 6 3 1 
7 3 1 

3.二叉树中结点的删除操作

删除的方式:

  • 基于数据元素值的删除
    1. SharedPointer< Tree<T> > remove(const T& value)
  • 基于结点的删除
    1. SharedPointer< Tree<T> > remove(TreeNode<T>* node)

二叉树中的结点删除:
技术分享图片

删除操作功能的定义:

  • void remove(BTreeNode<T>* node, BTree<T>*& ret)
    1. 将 node 为根结点的子树从原来的二叉树中删除
    2. ret 作为子树返回 ( ret 指向堆空间中的二叉树对象 )

删除功能函数的实现:
技术分享图片

在BTree.h中实现结点的删除操作:

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

        if( ret == NULL )
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory 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;
        }
    }
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);
        }

        return ret;
    }

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

        node = find(node);

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

        return ret;
    }

mian.cpp测试:

#include <iostream>
#include "BTree.h"

using namespace std;
using namespace StLib;

int main()
{
    BTree<int> bt;
    BTreeNode<int>* 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};

    SharedPointer< Tree<int> > sp = bt.remove(3);

    for(int i=0; i<5; i++)
    {
        TreeNode<int>* node = sp->find(a[i]);

        while( node )
        {
            cout << node->value << " ";
            node = node->parent;
        }

        cout << endl;
    }

    return 0;
}

运行结果为:




11 6 3 
7 3 

4.二叉树中结点的清除操作

清除操作的定义:

  • void clear()
    1. 将二叉树中的所有结点清除 ( 释放堆中的结点 )

二叉树中结点的清除:
技术分享图片

清除操作功能的定义:

  • free(node)
    1. 清除 node 为根结点的二叉树
    2. 释放二叉树中的每一个结点

技术分享图片

在BTree.h中实现结点的清除操作:

protected:
    virtual void free(BTreeNode<T>* node)
    {
        if( node != NULL )
        {
            free(node->left);
            free(node->right);

            if( node->flag() )
            {
                delete node;
            }
        }
    }
public:
    void clear()
    {
        free(root());

        this->m_root = NULL;
    }

5.小结

  • 二叉树的插入操作需要指明插入的位置
  • 插入操作必须正确处理指向父结点的指针
  • 插入数据元素时需要从堆空间中创建结点
  • 当数据元素插入失败时需要释放结点空间

  • 删除操作将目标结点所代表的子树移除
  • 删除操作必须完善处理父结点和子结点的关系
  • 清除操作用于销毁树中的每个结点
  • 销毁结点时判断是否释放对应的内存空间 ( 工厂模式 )

最终的BTree.h代码:
BTree.h

#ifndef BTREE_H
#define BTREE_H

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

namespace StLib
{

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 )
            {
                return 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 == obj )
        {
            return node;
        }
        else
        {
            if( node != NULL )
            {
                if( ret == NULL )
                {
                    ret = find(node->left, obj);
                }

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

        return ret;
    }

    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;
    }

    virtual void remove(BTreeNode<T>* node, BTree<T>*& ret)
    {
        ret = new BTree<T>();

        if( ret == NULL )
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory 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:
    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 node ...");
                }
            }
        }
        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;
    }

    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);
        }

        return ret;
    }

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

        node = find(node);

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

        return ret;
    }

    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);
    }

    int degree() const
    {
        return NULL;
    }

    int count() const
    {
        return NULL;
    }

    int height() const
    {
        return NULL;
    }

    void clear()
    {
        free(root());

        this->m_root = NULL;
    }

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

}

#endif // BTREE_H











以上是关于数据结构开发(23):二叉树中结点的查找插入删除与清除操作的主要内容,如果未能解决你的问题,请参考以下文章

二叉树的深度平衡是啥意思?

了解数据结构之平衡二叉树 (AVL)-插入和删除

二叉排序树中插入一个结点的时间复杂度是多少

题目3. 平衡二叉树算法查找树中某节点的时间复杂度是多少?

二叉树中的查找操作(按值查找按位查找)

数据结构开发(25):二叉树中属性操作层次遍历与典型遍历