【数据结构】二叉搜索树

文章目录

一、基本概念

二叉搜索树:

  1. 空树
  2. 左子树都小于根,右子树都大于根,且左右子树也是二叉搜索树

二、重要性质

二叉搜索树的中序遍历结果是升序的

三、增删查改

1. 查找

cpp 复制代码
bool find(const K& key)
{
    node* cur = root_;
    while(cur != nullptr)
    {
        if(key < cur->key_) cur = cur->left_;
        else if(key > cur->key_) cur = cur->right_;
        else return true;
    }
    return false;
}

2. 插入

cpp 复制代码
bool insert(const K& key)
{
    if(root_ == nullptr)
    {
        root_ = new node(key);
        return true;
    }

    node* cur = root_;
    node* parent = nullptr;
    while(cur != nullptr)
    {
        parent = cur;
        if(key < cur->key_) cur = cur->left_;
        else if(key > cur->key_) cur = cur->right_;
        else return false;
    }
    if(key < parent->key_) parent->left_ = new node(key);
    else parent->right_ = new node(key);
    return true;
}

3. 删除

记:要删除的结点为 d e l del del, d e l del del 的父节点为 p a r e n t parent parent

  1. d e l del del 左树为空
    • d e l del del 是 p a r e n t parent parent 的 l e f t left left, p a r e n t parent parent 的 l e f t left left 指向 d e l del del 的右树
    • d e l del del 是 p a r e n t parent parent 的 r i g h t right right, p a r e n t parent parent 的 r i g h t right right 指向 d e l del del 的右树
    • d e l del del 是根节点, d e l del del 指向 d e l del del 的右树
  2. d e l del del 右树为空
    • d e l del del 是 p a r e n t parent parent 的 l e f t left left, p a r e n t parent parent 的 l e f t left left 指向 d e l del del 的左树
    • d e l del del 是 p a r e n t parent parent 的 r i g h t right right, p a r e n t parent parent 的 r i g h t right right 指向 d e l del del 的左树
    • d e l del del 是根节点, d e l del del 指向 d e l del del 的左树
  3. d e l del del 左树右树都不为空
    • 找到 d e l del del 右树中的最左结点 t m p tmp tmp
    • 交换 t m p tmp tmp 和 d e l del del 的值
    • 删除 t m p tmp tmp
    • 该方法被称为替换法,替换删除后仍满足 d e l del del 大于左树,小于右树
cpp 复制代码
bool erase(const K& key)
{
    node* del = root_;
    node* parent = nullptr;

    //find the node to delete
    while(del != nullptr)
    {
        if(key < del->key_)
        {
            parent = del;
            del = del->left_;
        }
        else if(key > del->key_)
        {
            parent = del;
            del = del->right_;
        }
        else
        {
            if(del->left_ == nullptr)//(1)
            {
                if(del == root_)
                {
                    root_ = del->right_;
                }
                else
                {
                    if(del == parent->left_)
                    {
                        parent->left_ = del->right_;
                    }
                    else
                    {
                        parent->right_ = del->right_;
                    }
                }
            }
            else if(del->right_ == nullptr)//(2)
            {
                if(del == root_)
                {
                    root_ = del->left_;
                }
                else
                {
                    if(del == parent->left_)
                    {
                        parent->left_ = del->left_;
                    }
                    else
                    {
                        parent->right_ = del->left_;
                    }
                }
            }
            else//(3)
            {
                node* tmp = del->right_;
                node* tmp_parent = del;

                //find the leftest node tmp of the right subtree
                while(tmp->left_ != nullptr)
                {
                    tmp_parent = tmp;
                    tmp = tmp->left_;
                }
                swap(tmp->key_, del->key_);

                //delete tmp
                //tmp has no left child
                if(tmp == tmp_parent->left_)
                {
                    tmp_parent->left_ = tmp->right_;
                }
                else
                {
                    tmp_parent->right_ = tmp->right_;
                }
                del = tmp;
            }
            break;
        }
    }
    if(del->key_ == key)
    {
        delete del;
        return true;
    }
    else
    {
        return false;
    }
}

四、性能分析

二叉搜索树的核心操作就是查找。

插入前需要查找应该插入的位置,替换法删除也需要查找被替换结点。

因此二叉搜索树的性能主要取决于查找的效率。

一般情况下,查找操作的时间复杂度是 O ( l o g n ) O(logn) O(logn)。

当插入序列是一个有序序列时,二叉搜索树会退化成单支树,效率退化成 O ( n ) O(n) O(n)。

如何改进:AVL 树、红黑树

相关推荐
2501_933329551 天前
媒介宣发技术实践:Infoseek舆情系统的AI中台架构与应用解析
开发语言·人工智能·架构·数据库开发
[J] 一坚1 天前
嵌入式高手C
c语言·开发语言·stm32·单片机·mcu·51单片机·iot
odoo中国1 天前
Odoo 19技术教程 : 如何在 Odoo 19 中创建 Many2one 组件
开发语言·odoo·odoo19·odoo技术·many2one
借雨醉东风1 天前
程序分享--常见算法/编程面试题:旋转矩阵
c++·线性代数·算法·面试·职场和发展·矩阵
逻辑驱动的ken1 天前
Java高频面试考点场景题14
java·开发语言·深度学习·面试·职场和发展·求职招聘·春招
云泽8081 天前
笔试算法 - 双指针篇(二):四大经典求和题型 + 有效三角形计数问题
c++·算法
techdashen1 天前
Cloudflare 如何把一个大型代理拆成三个小服务来提升可靠性
开发语言·rust
geovindu1 天前
go: Chain of Responsibility Pattern
开发语言·设计模式·golang·责任链模式
十五年专注C++开发1 天前
WaitingSpinnerWidget: 一个高度可配置的自定义Qt等待加载动画组件
开发语言·c++·qt·waitingspinner
qeen871 天前
【数据结构】树的基本概念及存储
c语言·数据结构·c++·学习·