高级数据结构及算法:BST树(二叉查找树)

BST树(二叉查找树)

二叉查找树(Binary Search Tree),又被称为二叉搜索树
二叉查找树演示连接

在这里插入图片描述

1. 特点

  1. 任意节点的左子树不空, 则左子树上所有节点的key均小于它的根节点的key
  2. 任意节点的右子树不空, 则右子树上所有节点的key均大于它的根节点的key
  3. 任意节点的左,右子树也分别为二叉查找树
  4. 没有key相等的节点

2. 操作

2.1 查找

用递归的方式查找,判断是否有对应数

		// 查找
        bool Search(char val){
                return Search(m_root,val);
        }
        bool Search(Node* root,char val){
                if(nullptr == root) return false;          // 根节点为空,表示没找到
                if(root->val == val) return true;          // 根节点的值等于要找的值
                if(root->val < val){
                        return Search(root->right,val);    // 根节点的值小于要找的值,往右边找
                }else{
                        return Search(root->left,val);     // 根节点的值大于要找的值,往左边找
                }
        }

2.2 添加

用递归的方式对数做判断,插入左子树或右子树

        // 插入
        void Insert(char val){
                if(Search(val)) return;               // 如果找到了要插入的值,则不用插入
                m_root = Insert(m_root,val);          // 如果没找到,插入到根节点中
        }
        Node* Insert(Node* root,char val){
                if(nullptr == root) return new Node(val);       // 根节点为空,创建一个类空间,值为val
                if(root->val > val){
                        root->left = Insert(root->left,val);     // 如果根节点大于要插的数,插到左子树
                }else{
                        root->right = Insert(root->right,val);   // 如果根节点小于要插的数,插到右子树
                }
                return root;                      // 返回当前节点
        }

对一个BST二叉搜索数进行依次添加

#include <iostream>
using namespace std;

class Node{
public:
        char val;
        Node* left;
        Node* right;
        Node(int val):val(val),left(nullptr),right(nullptr){}
        Node(int val,Node* left,Node* right):val(val),left(left),right(right){}

        // void SetRight(Node* right){this->right = right;}
        // void SetLeft(Node* left){this->left = left;}
};

// 查找、添加、删除
class BSTree{
        Node* m_root = nullptr;     // 成员变量,初始化
public:
        // 查找
        bool Search(char val){
                return Search(m_root,val);
        }
        bool Search(Node* root,char val){
                if(nullptr == root) return false;          // 根节点为空,表示没找到
                if(root->val == val) return true;          // 根节点的值等于要找的值
                if(root->val < val){
                        return Search(root->right,val);    // 根节点的值小于要找的值,往右边找
                }else{
                        return Search(root->left,val);     // 根节点的值大于要找的值,往左边找
                }
        }

        // 插入
        void Insert(char val){
                if(Search(val)) return;               // 如果找到了要插入的值,则不用插入
                m_root = Insert(m_root,val);          // 如果没找到,插入到根节点中
        }
        Node* Insert(Node* root,char val){
                if(nullptr == root) return new Node(val);       // 根节点为空,创建一个类空间,值为val
                if(root->val > val){
                        root->left = Insert(root->left,val);     // 如果根节点大于要插的数,插到左子树
                }else{
                        root->right = Insert(root->right,val);   // 如果根节点小于要插的数,插到右子树
                }
                return root;                      // 返回当前节点
        }

        // 外部调用
        void Print(){
                preorder(m_root);
        }
        // 做前序遍历进行打印
        void preorder(const Node* root){
                if(nullptr == root) return;
                if(root->left) cout << root->val << "--" << root->left->val << endl;
                if(root->right) cout << root->val << "--" << root->right->val << endl;
                preorder(root->left);
                preorder(root->right);
        }
};

int main(){
        BSTree bst;
        bst.Insert('G');
        bst.Insert('T');
        bst.Insert('E');
        bst.Insert('F');
        bst.Insert('B');
        bst.Insert('X');

        bst.Print();
}

结果为:

G--E
G--T
E--B
E--F
T--X

上面结果可以得到对应数形图:
在这里插入图片描述

2.3 删除

替代删除,后继代替删除节点,然后删除后继;或者前驱代替删除节点,然后删除前驱

例如:
在这里插入图片描述删除节点“15”,即先找到该节点的右子树的最小值,即为“20”,把“15”替换成“20”,并删除原来的“20”,删除后经过递归返回“15”的右节点“30”
在这里插入图片描述
对上述程序继续进行删除节点的操作

#include <iostream>
using namespace std;

class Node{
public:
        char val;
        Node* left;
        Node* right;
        Node(int val):val(val),left(nullptr),right(nullptr){}
        Node(int val,Node* left,Node* right):val(val),left(left),right(right){}
};

// 查找、添加、删除
class BSTree{
        Node* m_root = nullptr;     // 成员变量,初始化
public:
        // 查找
        bool Search(char val){
                return Search(m_root,val);
        }
        bool Search(Node* root,char val){
                if(nullptr == root) return false;          // 根节点为空,表示没找到
                if(root->val == val) return true;          // 根节点的值等于要找的值
                if(root->val < val){
                        return Search(root->right,val);    // 根节点的值小于要找的值,往右边找
                }else{
                        return Search(root->left,val);     // 根节点的值大于要找的值,往左边找
                }
        }

        // 插入
        void Insert(char val){
                if(Search(val)) return;               // 如果找到了要插入的值,则不用插入
                m_root = Insert(m_root,val);          // 如果没找到,插入到根节点中
        }
        Node* Insert(Node* root,char val){
                if(nullptr == root) return new Node(val);       // 根节点为空,创建一个类空间,值为val
                if(root->val > val){
                        root->left = Insert(root->left,val);     // 如果根节点大于要插的数,去左子树插
                }else{
                        root->right = Insert(root->right,val);   // 如果根节点小于要插的数,去右子树插
                }
                return root;                      // 返回当前节点
        }

        // 删除
        void Remove(char val){
                m_root = Remove(m_root,val);
        }
        Node* Remove(Node* root,char val){
                if(nullptr == root) return nullptr;              // 如果没找到要删除的值,则返回空
                if(root->val < val){
                        root->right = Remove(root->right,val);      // 如果节点数小于要删的数,去右子树删
                }else if(root->val > val){
                        root->left = Remove(root->left,val);        // 如果节点数大于要删的数,去左子树删
                }else{                 // 如果找到了要删除的节点,分四种情况
                        if(nullptr == root->right && nullptr == root->left){      // 左右节点都为空,即是叶子节点
                                delete root;                  // 释放该节点
                                return nullptr;               // 返回空
                        }
                        if(nullptr == root->right){                               // 右子树为空,即只有左子树
                                Node* left = root->left;      // 保存左节点
                                delete root;                  // 释放该节点
                                return left;                  // 返回左节点
                        }
                        if(nullptr == root->left){                                // 左字数为空,即只有右字数
                                Node* right = root->right;    // 保存右节点
                                delete root;                  // 释放该节点
                                return right;                 // 返回右节点
                        }
                        // 当左右子树都存在
                        int minval = Minimun(root->right);           // 找到右子树的最小值
                        root->val = minval;                          // 把当前节点的值替换成该最小值
                        root->right = Remove(root->right,minval);    // 再去删除那个最小值的节点,层层递归后最终返回右节点
                }
                return root;
        }

        // 找根对应当前树的最小值
        int Minimun(Node* root){
                if(nullptr == root) throw runtime_error("root is null");           // 没有根,抛异常
                while(nullptr != root->left) root = root->left;        // 一直往左找,一直到左子树为空,返回当前节点值
                return root->val;
        }

        // 外部调用
        void Print(){
                preorder(m_root);
        }
        // 做前序遍历
        void preorder(const Node* root){
                if(nullptr == root) return;
                if(root->left) cout << root->val << "--" << root->left->val << endl;
                if(root->right) cout << root->val << "--" << root->right->val << endl;
                preorder(root->left);
                preorder(root->right);
        }
};

int main(){
        BSTree bst;
        bst.Insert('G');
        bst.Insert('T');
        bst.Insert('E');
        bst.Insert('F');
        bst.Insert('B');
        bst.Insert('X');

        bst.Remove('E');
        bst.Print();
}

结果为:

G--F
G--T
F--B
T--X

上面结果可以得到对应数形图:
在这里插入图片描述

我们将两张图对比,可以清楚的发现删除过程为:在E的右子树下找到最小的值即F,把E替换为F,并将之前的F删掉

2.4 优化

让类型变换更灵活,从终端输入

#include <iostream>
using namespace std;

template <typename T>
class _Node{
public:
        T val;
        _Node* left;
        _Node* right;
        _Node(const T& val):val(val),left(nullptr),right(nullptr){}
        _Node(const T& val,_Node* left,_Node* right):val(val),left(left),right(right){}
};

template <typename T>
// 查找、添加、删除
class BSTree{
        typedef _Node<T> Node;      // 统一替换
        Node* m_root = nullptr;     // 成员变量,初始化
public:
        // 查找
        bool Search(const T& val){
                return Search(m_root,val);
        }
        bool Search(Node* root,const T& val){
                if(nullptr == root) return false;          // 根节点为空,表示没找到
                if(root->val == val) return true;          // 根节点的值等于要找的值
                if(root->val < val){
                        return Search(root->right,val);    // 根节点的值小于要找的值,往右边找
                }else{
                        return Search(root->left,val);     // 根节点的值大于要找的值,往左边找
                }
        }

        // 插入
        void Insert(const T& val){
                if(Search(val)) return;               // 如果找到了要插入的值,则不用插入
                m_root = Insert(m_root,val);          // 如果没找到,插入到根节点中
        }
        Node* Insert(Node* root,const T& val){
                if(nullptr == root) return new Node(val);       // 根节点为空,创建一个类空间,值为val
                if(root->val > val){
                        root->left = Insert(root->left,val);     // 如果根节点大于要插的数,去左子树插
                }else{
                        root->right = Insert(root->right,val);   // 如果根节点小于要插的数,去右子树插
                }
                return root;                      // 返回当前节点
        }

        // 删除
        void Remove(const T& val){
                m_root = Remove(m_root,val);
        }
        Node* Remove(Node* root,const T& val){
                if(nullptr == root) return nullptr;              // 如果没找到要删除的值,则返回空
                if(root->val < val){
                        root->right = Remove(root->right,val);      // 如果节点数小于要删的数,去右子树删
                }else if(root->val > val){
                        root->left = Remove(root->left,val);        // 如果节点数大于要删的数,去左子树删
                }else{                 // 如果找到了要删除的节点,分四种情况
                        if(nullptr == root->right && nullptr == root->left){      // 左右节点都为空,即是叶子节点
                                delete root;                  // 释放该节点
                                return nullptr;               // 返回空
                        }
                        if(nullptr == root->right){                               // 右子树为空,即只有左子树
                                Node* left = root->left;      // 保存左节点
                                delete root;                  // 释放该节点
                                return left;                  // 返回左节点
                        }
                        if(nullptr == root->left){                                // 左字数为空,即只有右字数
                                Node* right = root->right;    // 保存右节点
                                delete root;                  // 释放该节点
                                return right;                 // 返回右节点
                        }
                        // 当左右子树都存在
                        T minval = Minimun(root->right);           // 找到右子树的最小值
                        root->val = minval;                          // 把当前节点的值替换成该最小值
                        root->right = Remove(root->right,minval);    // 再去删除那个最小值的节点,返回右节点
                }
                return root;
        }

        // 找整个树的最小值
        T Minimun(Node* root){
                if(nullptr == root) throw runtime_error("root is null");           // 没有根,抛异常
                while(nullptr != root->left) root = root->left;        // 一直往左找,一直到左子树为空,返回当前节点值
                return root->val;
        }

        // 外部调用
        void Print(){
                preorder(m_root);
        }
        // 做前序遍历
        void preorder(const Node* root){
                if(nullptr == root) return;
                if(root->left) cout << root->val << "--" << root->left->val << endl;
                if(root->right) cout << root->val << "--" << root->right->val << endl;
                preorder(root->left);
                preorder(root->right);
        }
};

int main(){
        BSTree<int> intbst;
        int n;
        while(cin >> n){
                intbst.Insert(n);
        }
        intbst.Print();
}

结果为:

12 8 25 5 18 30 20
12--8
12--25
8--5
25--18
25--30
18--20

上面结果可以得到对应数形图:
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值