【数据结构】63_二叉树中的结点插入操作

BitLuminaryX
• 阅读 1760

需要考虑的问题

是否需要在二叉树的任意结点处插入子节点? (左右子树是否已满)
是否需要指定新数据元素(新节点)的插入位置?(左子树、右子树)

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

enum BTNodePos
{
    ANY,
    LEFT,
    RIGHT
};

插入的方式

  • 插入新结点

    • bool insert(TreeNode<T> *node);
    • bool insert(TreeNode<T> *node, BTNodePos pos);
  • 插入数据元素

    • bool insert(const T &value, TreeNode<T> *parent);
    • bool insert(const T &value, TreeNode<T> *parent, BTNodePos pos);

新结点的插入

【数据结构】63_二叉树中的结点插入操作

指定位置的结点插入

bool insert(n, np, pos)

【数据结构】63_二叉树中的结点插入操作

插入新结点

【数据结构】63_二叉树中的结点插入操作

插入数据元素

【数据结构】63_二叉树中的结点插入操作

编程实验:二叉树的插入操作

文件: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<T>
{
public:
    BTree() = default;

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

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

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

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

        return ret;
    }

    bool insert(const T &value, TreeNode<T> *parent) override
    {
        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 != nullptr)
        {
            node->value = value;
            node->parent = parent;

            ret = insert(node, pos);

            if (!ret)
            {
                delete node;
            }
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to create node ...");
        }

        return ret;
    }

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

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

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

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

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

    int degree() const override
    {
        return 0;
    }

    int count() const override
    {
        return 0;
    }

    int height() const
    {
        return 0;
    }

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

    ~BTree()
    {
        clear();
    }

protected:
    BTree(const BTree<T>&) = default;
    BTree<T>& operator = (const BTree<T>&) = default;

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

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

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

        return ret;
    }

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

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

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

        return ret;
    }

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

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

        return ret;
    }
};

}

#endif // BTREE_H

文件:main.cpp

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

using namespace std;
using namespace DTLib;

int main()
{
    BTree<int> bt;
    BTreeNode<int> *n = nullptr;

    bt.insert(1, nullptr);

    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

小结

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

To be continued

思考:如何实现 BTree (二叉树结构)的结点删除操作和清除操作
SharedPointer<Tree<T>> remove(const T &value) override
{
    // ...
}

SharedPointer<Tree<T>> remove(TreeNode<T> *node) override
{
    // ...
}

void clear() override
{
    // ...
}

以上内容整理于狄泰软件学院系列课程,请大家保护原创!

点赞
收藏
评论区
推荐文章
似梦清欢 似梦清欢
2年前
树与二叉树
二叉树层次建树二叉树(BinaryTree)是由有限个结点组成的集合,它或者为空集合,或者仅含一个根结点,或者由一个根结点和两棵互不相交的左、右子树组成。树为空即根节点为空。二叉树的基本形态如下图:a:空的二叉树,treeNULL。b:只有空节点的二叉树,
Wesley13 Wesley13
3年前
java——平衡二叉树 AVLTree、AVLMap、AVLSet
平衡二叉树:对于任意一个节点,左子树和右子树的高度差不能超过1packageDate_pacage;importjava.util.ArrayList;publicclassAVLTree<KextendsComparable<K,V{privateclassNod
Easter79 Easter79
3年前
test md table
aaaaAaaAaaaAaaAaaaAaaAaaaAaa|aaaa|Aaa|Aaaa|Aaa||:|:|:|:||Aaaa|Aaa|Aaaa|Aaa|插入方式描述旋转方式说明LL在a的左子树根节点的左子树上插入节点
22 22
4年前
动图图解二叉查找树的基本原理及其实现
本文为系列专题的第12篇文章。1.2.3.4.5.6.7.8.9.10.1.是什么?二叉查找树(BinarySearchTree)必须满足以下特点:若左子树不为空,则左子树的所有结点值皆小于根结点值若右子树不为空,则右子树的所有结点值皆大于根结点值左右子树也是二叉排序树如下图,是一颗二叉查找树:如果你对二叉查找树进行中序
Kubrnete Kubrnete
4年前
二叉树题集(持续更新中)
对于二叉搜索树,我们规定任一结点的左子树仅包含严格小于该结点的键值,而其右子树包含大于或等于该结点的键值。1\.求二叉搜索树最大深度输入格式:输入给出一行整数序列作为二叉搜索树的键值,数字间以空格分隔,输入0结束(0不计入该二叉树键值)。输入样例:8685109110输出样例:4常规的求二叉搜索树深度的做法是递
Wesley13 Wesley13
3年前
JAVA递归实现线索化二叉树
JAVA递归实现线索化二叉树基础理论首先,二叉树递归遍历分为先序遍历、中序遍历和后序遍历。先序遍历为:根节点左子树右子树中序遍历为:左子树根节点右子树后序遍历为:左子树右子树根节点(只要记住根节点在哪里就是什么遍历,且都是先左再右)线索化现在有这么一棵二叉树,它的数据结
Wesley13 Wesley13
3年前
Java实现 LeetCode 814 二叉树剪枝 (遍历树)
814\.二叉树剪枝给定二叉树根结点root,此外树的每个结点的值要么是0,要么是1。返回移除了所有不包含1的子树的原二叉树。(节点X的子树为X本身,以及所有X的后代。)示例1:输入:\1,null,0,0,1\输出:\1,null,0,null,1\解释:
Stella981 Stella981
3年前
LeetCode(98): 验证二叉搜索树
Medium!题目描述:给定一个二叉树,判断其是否是一个有效的二叉搜索树。一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数。节点的右子树只包含大于当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。示例 1:输入:2/\
Wesley13 Wesley13
3年前
PHP数据结构与算法:二叉树
一、定义二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(leftsubtree)和“右子树”(rightsubtree)。二、特性1.在二叉树的第i层上至多有2^(i1)个结点(i0)2.深度为k的二叉树至多有2^k1个结点(k0)3.对于任意一棵二叉树,如果其叶结点数为N0,而
Wesley13 Wesley13
3年前
98. 验证二叉搜索树
题目描述给定一个二叉树,判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数。节点的右子树只包含大于当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。输入:5/\14 /\ 
菜园前端 菜园前端
2年前
什么是二叉树?
原文链接:什么是二叉树?树中每个节点最多只能有两个子节点,在JavaScript中一般都是通过Object来模拟二叉树。常用操作前序遍历中序遍历后序遍历前序遍历根左右。口诀:1.访问根节点2.对根节点的左子树进行前序遍历3.对根节点的右子树进行前序遍历通过