二叉搜索树的实现

定义节点

节点的定义比较简单,需定义好 索引key,左右子节点,父节点以及用户想要保存的自定义数据

template <typename T>
class Node{
public:
    Node(int key,T t,Node* left,Node *right,Node *parent){
        this->t = t;
        this->key = key;
        this->left = left;
        this->right = right;
        this->parent = parent;
    };
    Node *left;
    Node *right;
    Node *parent;
    int key;
    //定义自己的数据结构
    T t;
};
创建树

就是自己定义一个根起点就好

	Node<string> *root;//根节点
节点插入

节点插入比较简单,按照二叉搜索树的定义进行处理就行,索引(key)小的放左边,大的放右边,代码接口(具体实现可参考后面提供的源文件

bool BinarySearchTree::insert(int key);
节点删除

节点的删除复杂一些,之所以复杂也是为了在做了删除操作后,此树依然为一棵二叉搜索树
其实也就是要处理的情况比较多而已,每一种列出来单独处理,注意细节处理, 就没问题了,

情况一:被删除的节点(红框中代表被删除的节点) 没有子节点,直接删除
在这里插入图片描述
情况二:被删除的节点(红框中代表被删除的节点)只有一个子节点(左子节点或右子节点),将被删除的节点的子节点连接到父节点,

在这里插入图片描述
情况三:被删除的节点有2个子节点时,就不能直接删除了,需要做以下几步:

  • 找到一个可直接删除的节点,也就是前2种情况
  • 将找到的节点与当前节点交换位置
  • 删除节点
  • 注意必须保证二叉树搜索树的性质
    为了保证二叉树的性质(小的在左子节点,大的在右子节点),当前的方法就是找到“前驱节点”或“后继节点”来交换位置。
  • “前驱节点”:左子树最大节点
  • “后继节点”:右子树的最小节点

简单证明,当前节点与前驱节点或后继节点交换位置后,不改变二叉搜索树性质
如下图所示 “A、C、F”都是单个节点,“B、D ”是一个节点集合代表中间所有的节点。
根据前驱节点的特点和二叉树的性质:
已知B<A 同时 B<C,那么将A和C调换位置,B集合中任何节点 依然都小于A或C
同理
已知D>A 同时 D>F,那么将A和F调换位置,D集合中任何节点 依然大于A或F

在这里插入图片描述
实际删除时,只需要找一种节点就行了,在这里我使用的是后继节点,现在假设已经找到后继节点了,简单起见,将后继节点分为以下4种情况

  1. 后继节点为删除节点的右子节点------后继节点 没有子节点,则可以直接删除
  2. 后继节点为删除节点的右子节点------后继节点 有子节点(只会是单子节点而且是右子节点),则将子节点与父节点连接
  3. 后继节点不是删除节点的右子节点------后继节点 没有子节点,则可以直接删除
  4. 后继节点不是删除节点的右子节点------后继节点 有子节点(只会是单子节点而且是右子节点),则将子节点与父节点连接
    下图代表了后继节点与被删节点存在的几种位置分布,红框代表要删除的节点,绿框代表后继节点,注意后继节点一定没有左子节点,右子节点可以是单个节点 也可以是树
    在这里插入图片描述
代码实现

整个二叉搜索树的类文件,只包含了增加和删除操作,其中有qt的打印,注释即可

头文件

#ifndef BINARYSEARCHTREE_H
#define BINARYSEARCHTREE_H

#include <QObject>

template <typename T>
class Node{

public:

    Node(int key,T t,Node* left,Node *right,Node *parent){
        this->t = t;
        this->key = key;
        this->left = left;
        this->right = right;
        this->parent = parent;
    };
    Node(){};

    Node(Node &node){
        this->t = node.t;
        this->key = node.key;
        this->left = node.left;
        this->right = node.right;
        this->parent = node.parent;
    };

    Node *left;
    Node *right;
    Node *parent;

    int key;
    //定义自己的数据结构
    T t;
};
using namespace std;
//template <typename T>
class BinarySearchTree
{

public:
    BinarySearchTree();

    bool insert(int key);
    bool insert(Node<string>* &n);
    bool remove(int key);
    bool update(int key);

//private:
    Node<string> *root;
    int treedepth;
};

#endif // BINARYSEARCHTREE_H

源文件

#include "binarysearchtree.h"
#include <QDebug>

BinarySearchTree::BinarySearchTree():root(nullptr)
{

    treedepth = 0;
}

//默认需要保存的数据值是与key一样的字符串,
bool BinarySearchTree::insert(int key)
{

    if(root == nullptr){

        root = new Node<string>(key,"",nullptr,nullptr,nullptr);

    }else{

        Node<string> * curnode = root;
        int level = 0;
        while (curnode != nullptr) {

            int curkey = curnode->key;
            level++;
            if(curkey < key){

                if(curnode->right == nullptr){

                    Node<string> *newnode = new Node<string>(key,"",nullptr,nullptr,nullptr);
                    curnode->right = newnode;
                    newnode->parent = curnode;
                    if(treedepth < level)
                        treedepth = level;
                    qDebug()<<"插入成功,右值:"<<key<<",深度:"<<treedepth;
                    break;
                }else
                    curnode = curnode->right;

            }else if(curkey > key){

                if(curnode->left == nullptr){
                    if(treedepth < level)
                        treedepth = level;
                    Node<string> *newnode = new Node<string>(key,"",nullptr,nullptr,nullptr);

                    curnode->left = newnode;
                    newnode->parent = curnode;
                    qDebug()<<"插入成功,左值:"<<key<<",深度:"<<treedepth;
                    break;
                }else
                    curnode = curnode->left;


            }else{

                //插入相同输入
                qDebug()<<"插入失败:"<<key;
                return false;
            }

        }


    }

    return true;
}

bool BinarySearchTree::insert(Node<string>* &n)
{


}


bool BinarySearchTree::remove(int key){


    qDebug()<<"删除节点:"<<key;
    //找到要删除的节点
    Node<string> * curnode = root;

    if(root->key == key){
        qDebug()<<"不能删除根节点:";
        return false;
    }
    while (curnode != nullptr) {

        qDebug()<<"删除节点:"<<curnode->key;
        int curkey = curnode->key;
        if(curkey < key){

            curnode = curnode->right;

        }else if(curkey > key){

            curnode = curnode->left;

        }else{

            //子节点都为空,直接删除
            if(curnode->left == nullptr && curnode->right == nullptr)
            {

                qDebug()<<"左右节点都为空";
                if(curkey < curnode->parent->key){
                    curnode->parent->left = nullptr;
                    qDebug()<<"删除左节点成功:"<<key;
                }else if(curkey > curnode->parent->key){
                    curnode->parent->right = nullptr;
                    qDebug()<<"删除右节点成功:"<<key;
                }
                delete curnode;
                curnode = nullptr;
                break;
            }
            else if(curnode->left != nullptr && curnode->right == nullptr)
            {
                /*
                 * 有且只有一个子节点时,可以将子节点替换到当前节点的位置,然后删除
                 * 每一个节点都是按搜索二叉树(右子树大,左子树小)的规则插入的,所以在这种情况下子节点替换当前节点,也会满足二叉搜索树的规则
                 *
                 * 有一个左子节点,右节点空
                */


                if(curkey < curnode->parent->key){
                    curnode->parent->left = curnode->left;
                    curnode->left->parent = curnode->parent;
                    qDebug()<<"删除左节点成功:"<<key;
                }

                if(curkey > curnode->parent->key){
                    curnode->parent->right = curnode->left;
                    curnode->left->parent = curnode->parent;
                    qDebug()<<"删除右节点成功:"<<key;
                }
                delete curnode;
                curnode = nullptr;
                break;
            }else if(curnode->left == nullptr && curnode->right != nullptr)
            {//有一个右子节点,左节点空

                if(curkey < curnode->parent->key){
                    curnode->parent->left = curnode->right;
                    curnode->right->parent = curnode->parent;
                    qDebug()<<"删除左节点成功:"<<key;
                }

                if(curkey > curnode->parent->key){
                    curnode->parent->right = curnode->right;
                    curnode->right->parent = curnode->parent;
                    qDebug()<<"删除右节点成功:"<<key;
                }
                delete curnode;
                curnode = nullptr;
                break;

            }else if(curnode->left != nullptr && curnode->right != nullptr){
                /*
                 * 有2个子节点时,
                 * 1、需要先找到其后继结点(右子树中最小的子节点),找前驱节点(左子树中最大的子节点)也是可以的?
                 * 2、将后继节点与当前节点替换, 然后删除当前节点
                */
                Node<string> *successorNode  = curnode->right;


                while (successorNode->left != nullptr ) {

                    successorNode = successorNode->left;
                }


                qDebug()<<"后继节点:"<<successorNode->key;



                //只交换节点的key和值
                Node<string> tmpnode(*successorNode);

                curnode->key = successorNode->key;
                curnode->t = successorNode->t;

                successorNode->key = tmpnode.key;
                successorNode->t = tmpnode.t;




                //后继节点是当前节点的右节点
                if(curnode->right->key == successorNode->key){


                    if(successorNode->right == nullptr){
                        curnode->right = nullptr;
                        delete successorNode;
                    }else{

                        curnode->right = successorNode->right;
                        successorNode->right->parent = curnode;

                        delete successorNode;
                    }

                }else{

                    if(successorNode->right == nullptr){

                        successorNode->parent->left = nullptr;
                        delete successorNode;
                    }else{

                        successorNode->parent->left = successorNode->right;

                        successorNode->right->parent = successorNode->parent;

                        delete successorNode;
                    }

                }



                break;


            }
        }
    }
}

bool BinarySearchTree::update(int key){



}

二叉树实现与显示qt工程链接

qt create打开就行,我的qt版本是5.14
二叉搜索树的实现及显示
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dai1396734

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值