跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
|注册
博客列表

目录

  1. C++ 二叉搜索树原理与高效实现
  2. 一、二叉搜索树介绍
  3. 二、特点剖析
  4. 三、二叉搜索树实现
  5. (1)结构创建
  6. (2)插入节点
  7. (3)中序遍历
  8. (4)查找节点
  9. (5)删除节点
  10. (6)析构
  11. (7)拷贝构造
C++算法

C++ 二叉搜索树原理与高效实现

本文深入剖析了 C++ 中二叉搜索树(BST)的原理与实现。介绍了 BST 的定义及特点,即左子节点小于父节点,右子节点大于父节点。详细讲解了结构创建、插入、中序遍历、查找、删除及析构等核心操作的逻辑与代码实现,重点阐述了删除节点时处理单孩子、双孩子的情况以及拷贝构造的方法,提供了内存安全的现代 C++ 实现范式。

并发大师发布于 2026/3/29更新于 2026/4/131 浏览
C++ 二叉搜索树原理与高效实现

C++ 二叉搜索树原理与高效实现

一、二叉搜索树介绍

二叉搜索树(Binary Search Tree, BST)又称二叉排序树,是一种基础且强大的数据结构。它通过特定的节点排列规则实现了数据的有序存储,在算法设计与内存优化中扮演核心角色。

二、特点剖析

二叉搜索树可以为空树,其语言描绘特征如下:

  1. 从根节点开始,左子节点的值小于父节点。
  2. 从根节点开始,右子节点的值大于父节点。
  3. 左右子树也分别为二叉搜索树。

BST 结构示例

三、二叉搜索树实现

(1)结构创建

实现一棵二叉搜索树,需要定义节点结构和功能结构。

节点结构包含左右子节点(left, right)和数据存储变量(data)。

(2)插入节点

插入节点需要根据数据的大小判断插在左右节点的 nullptr 位置。这里使用循环实现。

注意: 需要使用其他节点代替 node 去移动,否则 node 每次都不是指向根节点。

// 插入节点
void Insert(const T& data) {
    // 如果根节点为空
    if (node == nullptr) {
        node = new Node(data);
        return;
    }
    // 根据数据大小查找
    Node* parent = nullptr;
    Node* cur = node;
    while (cur) {
        // 记录父节点
        parent = cur;
        // 如果小于父节点
        if (data < cur->data) {
            cur = cur->left;
        } else {
            cur = cur->right;
        }
    }
    // 此时已经到了节点为空的位置
    // 如果小于父节点
    if (data < parent->data) {
        // 插在父节点左侧
        parent->left = new Node(data);
        return;
    }  {
        
        parent->right =  (data);
        ;
    }
}
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog

更多推荐文章

查看全部
  • Linux 下 Vim 编辑器使用详解
  • Mac 系统 OpenClaw 本地 AI 执行引擎安装与配置指南
  • Java AWT 布局管理器详解
  • Visual C++ 运行库安装故障诊断与修复指南
  • Testsigma 开源自动化测试平台实战部署指南
  • AI 辅助 C++ 正确使用 override 关键字
  • LeetCode 206:反转链表
  • C++ 多态核心原理与虚函数表详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown 转 HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online

  • HTML 转 Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

else
// 插在父节点右侧
new
Node
return

(3)中序遍历

中序遍历调用递归完成:先遍历左子树,然后父节点,然后右子树。

// 中序遍历
void Inorder() {
    _Inorder(node);
}

void _Inorder(Node* ptr) {
    // 遇到空就返回
    if (ptr == nullptr) {
        return;
    }
    _Inorder(ptr->left);
    cout << ptr->data << " ";
    _Inorder(ptr->right);
}

(4)查找节点

找到对应节点之后,然后返回即可。根据要找的数据大小去查找,最多查找次数就是二叉树的深度次。

// 查找数据
bool Find(const T& data) {
    // 如果为空树,返回
    if (node == nullptr) {
        return false;
    }
    Node* cur = node;
    // 找节点
    while (cur) {
        // 如果 data 大于父节点,右边找,否则左边找
        if (data > cur->data) {
            cur = cur->right;
        } else if (data < cur->data) {
            cur = cur->left;
        } else {
            return true;
        }
    }
    // 如果出循环了还没有返回就说明没有找到
    return false;
}

(5)删除节点

删除节点需要考虑以下三种情况(重点是比较节点数据大小):

  1. 该节点无孩子节点:先删,然后置空。
  2. 该节点有一个孩子节点:先连接再删。

    注意: 这两种情况可以概括为一类,参考下面代码注释。

  3. 该节点有两个孩子节点:我们需要找一个特定大小的节点去替代它。

    替代思路:让它的左子树最大值或者右子树最小值去替换,然后删除它(以左子树 max 为例)。

解释: 例如下面这幅图,我们要删除 3。

  1. 先找到目标节点 cur(3),然后找目标节点左子树的最大值 left_max。
  2. 交换目标节点 cur 和最大值 left_max 的数据。
  3. 这里需要标记 left_max 的父节点为 parent。

第一种情况:

  1. 因为找的是左子树的最大值,所以只可能父节点 parent 的右边还存在子节点,将它连接在 parent 的右边。
  2. 再将 cur 指向 left_max,删除。

第二种情况:

  1. 因为找的是左子树的最大值,可能 parent 的左边还存在子节点。
  2. 再将 cur 指向 left_max,删除。

(6)析构

我们可以利用上面的'删除节点' + '根节点是否为空循环'来不断析构。

注意: 上面我们的析构是利用第三方指针 cur 代替 node 删除的,所以当二叉树只有一个根节点删除后需要考虑置空,这样才可以利用到循环。

// 析构
~BST() {
    while (node) {
        Erase(node->data);
        cout << "删除成功" << endl;
    }
}

(7)拷贝构造

拷贝构造可以利用递归遍历不断开新节点。

注意: 递归左右节点时要连接起来。

// 拷贝构造
BST(const BST<T>& ptr) {
    // 如果拷贝对象是空
    if (ptr.node == nullptr) {
        return;
    }
    // 这里的 ptr 是拷贝的对象,node 是待拷贝的对象的根节点
    node = Copy(node, ptr.node);
}

Node* Copy(Node* _node, Node* copy_node) {
    if (copy_node == nullptr) {
        return nullptr;
    }
    // 前序拷贝
    _node = new Node(copy_node->data);
    // 空间是开辟成功了,但是这里 node 的左右子树,没有连接,需要接收 copy 的返回值才能完成连接
    _node->left = Copy(_node->left, copy_node->left);
    _node->right = Copy(_node->right, copy_node->right);
    // 返回根节点
    return _node;
}
C++23 常用特性详解
  • MuJoCo 足式机器人强化学习:URDF 转 XML 配置指南
  • 飞书 OpenClaw 机器人接入指南:基于长连接无需服务器
  • 西门子 S7-1200 PLC 与爱普生机器人 Modbus TCP 通讯配置
  • 解决 Python pip 报错 Preparing metadata (pyproject.toml) failed
  • 医疗 AI 场景下模型融合与集成策略深度解析
  • OpenClaw 新手指南:AI 机器人搭建与配置全攻略
  • 操作系统智能助手 OS Copilot 新功能测评
  • Matlab 一键生成 FPGA 存储器初始化文件:MIF、COE 及 TXT 格式详解
  • WebRTC 播放器横向测评:H5 低延迟直播方案选型
  • Eino 组件核心篇:Embedding 功能解析与使用指南
  • 2026 国内 AI 编程套餐横评:选型指南与避坑建议