3.【C++进阶】二叉搜索树

本博客梳理二叉搜索树基本概念及底层原理

一、二叉搜索树概念

1.根本法则:左<根<右

对这棵树而言,任意一个节点N,左子树的节点值小于N,右子树的节点值大于N

2.map/set系列容器的底层

map/set/multimap/multiset系列容器的底层就是二叉搜索树,map和set不支持插入相等值,multimap/multiset支持插入相等值

二、二叉搜索树性能

最差情况下,二叉搜索树变成单支树,则查找效率变成O(N)

三、二叉搜索树的底层原理

以下三个基本操作均有对应OJ题,点击即可跳转

1.二叉搜索树的查找

直接根据搜索树的性质查找即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        TreeNode* cur = root;
        while(cur)
        {
            if(val < cur->val)
                cur = cur->left;
            else if(val > cur->val)
                cur = cur->right;
            else
                return cur;
        }
        return nullptr;
    }
};

2.二叉搜索树的插入

(1)树为空,直接新增节点,赋值给root指针
(2)树不为空,按二叉搜索树性质寻找插入位置,找到空位置后插入新节点
(3)如果支持插入相等的值,则寻找插入位置时,需要统一向左or向右走,保持逻辑一致性

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) 
    {
        if(root == nullptr)
        {
            root = new TreeNode(val);
            return root;
        }

        TreeNode* cur = root;
        TreeNode* parent = nullptr;
        //寻找插入位置
        while(cur)
        {
            if(val < cur->val)
            {
                parent = cur;
                cur = cur->left;
            }
            else if(val > cur->val)
            {
                parent = cur;
                cur = cur->right;
            }
        }

        cur = new TreeNode(val);
        if(val < parent->val)
            parent->left = cur;
        else
            parent->right = cur;
        return root;
    }
};

3.二叉搜索树的删除

删除一个节点可能出现的四种情况:
(1)目标节点N左右孩子均为空
(2)目标节点N左为空,右不为空
(3)目标节点N右为空,左不为空
(4)目标节点N左右均不为空
对应解决方案
(1)情况1和情况2合并,把N的父亲指向N的右孩子,然后删除N
(1)
(2)情况3:把N的父亲指向N的左孩子,然后删除N
(2)
(3)情况4:采用替换法,找左子树的最大or右子树的最小来替换目标待删节点,然后目标待删节点会转换成上面的情况,再删除即可

(3)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        //先查找key所在的位置
        TreeNode* parent = nullptr;
        TreeNode* cur = root;
        while(cur)
        {
            if(key < cur->val)
            {
                parent = cur;
                cur = cur->left;
            }
            else if(key > cur->val)
            {
                parent = cur;
                cur = cur->right;
            }
            else
            {
                //执行删除逻辑,然后跳出循环
                if(cur->left == nullptr)//左为空,右为空or不为空
                {
                    if(cur == root)//注意如果cur就是根,则没有parent,要特殊处理
                    {
                        root = cur->right;
                    }
                    else
                    {
                        if(cur == parent->left)
                            parent->left = cur->right;
                        else
                            parent->right = cur->right;
                    }
                    delete cur;
                }
                else if(cur->right == nullptr)//此时cur->left一定不为空
                {
                    if(cur == root)//注意如果cur就是根,则没有parent,要特殊处理
                    {
                        root = cur->left;
                    }
                    else
                    {
                        if(cur == parent->left)
                            parent->left = cur->left;
                        else
                            parent->right = cur->left;
                    }
                    delete cur;
                }
                else
                {
                    //找右的最小来替换当前cur
                    //转换成上面的情况
                    TreeNode* minRight = cur->right;
                    TreeNode* minRightParent = cur;

                    while(minRight->left)
                    {
                        minRightParent = minRight;
                        minRight = minRight->left;
                    }

                    swap(cur->val, minRight->val);

                    //注意minRight右可能不为空
                    if(minRight == minRightParent->left)
                        minRightParent->left = minRight->right;
                    else
                        minRightParent->right = minRight->right;
                    delete minRight;
                    
                }
                return root;
            }
        }
        return root;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值