当前位置: 首页 > news >正文

从零开始掌握二叉搜索树(C++ 完整实现与深度解析)

二叉搜索树(Binary Search Tree, BST)是最基础、最经典的树形数据结构之一。它不仅是理解更高级树结构(如 AVL 树、红黑树、B 树)的基石,在许多实际场景中也直接发挥作用。本文将从定义出发,手把手带你用 C++ 实现一个完整的二叉搜索树,并深入分析其性能与局限。

一,什么是二叉搜索树?

二叉搜索树 是一种特殊的二叉树,它满足以下性质:

1,若左子树非空,则左子树上所有节点的值 均小于 根节点的值。

2,若右子树非空,则右子树上所有节点的值 均大于 根节点的值。

3,左、右子树本身也各是一棵二叉搜索树。

(通常我们默认树中不存在值相等的节点;若需支持重复键值,可通过计数或规则约定处理,本文以无重复为例。)

得益于这种有序性,BST 能够以 O(h)的时间完成查找、插入、删除操作,其中 h 是树的高度。最优情况下 h=log⁡n,退化为链表时 h=n。

二,节点定义与基本框架

我们用 C++ 模板来实现,以便支持不同数据类型。节点结构包含数据域、左右孩子指针。为便于管理内存,这里使用原始指针,并在析构函数中递归释放整棵树。

template<class T> struct TreeNode { T _key; TreeNode<T>* _left; TreeNode<T>* _right; TreeNode(const T& key) :_key(key) , _left(nullptr) ,_right(nullptr) { } }; template<class T> class BSTree { struct Less { bool operator()(const T& x, const T& y) { return x < y; } }; struct Greater { bool operator()(const T& x, const T& y) { return x > y; } }; typedef TreeNode<T> Node; public: BSTree() :_root(nullptr) { } ~BSTree() { _postorder_traversal(_root); } private: void _postorder_traversal(Node* root) { if (root == nullptr) return; _postorder_traversal(root->_left); _postorder_traversal(root->_right); delete root; } Node* _root;

(一),查找

从根节点开始,若目标值等于当前节点值则找到;若小于则进入左子树;若大于则进入右子树。递归与非递归版本都很简洁。

bool find(const T& key)const { if (_root == nullptr) return false; Node* root = _root; while (root) { if (key < root->_key) { root = root->_left; } else if (key > root->_key) { root = root->_right; } else { return true; } } return false; }

(二),插入

插入的过程与查找类似:寻找合适的位置(即查找失败时所在的空位),然后将新节点挂载上去。下图展示了插入的过程。

bool insert(const T& key) { Node* root = _root; Node* parent = nullptr; while (root) { if (Less()(key, root->_key)) { parent = root; root = root->_left; } else if (Greater()(key, root->_key)) { parent = root; root = root->_right; } else { return false; } } Node* newnode = new Node(key); if (_root == nullptr) { _root = newnode; } else { if (Less()(key, parent->_key)) parent->_left = newnode; else parent->_right = newnode; } return true; }

(三),删除

删除操作需要处理三种情况:

1,叶子节点:直接删除。

2,只有一个孩子:用其孩子替换该节点。

3,有两个孩子:找到 后继节点(左右都不为空,找到左子树的最大节点或者右子树的最小节点),本文是找左子树的最大节点,右子树最小节点同理。然后将要删除的值与该节点的值交换,交换之后,再将其删除。

bool erase(const T& key) { Node* node = _root; Node* parent = nullptr; while (node) { if (key < node->_key) { parent = node; node = node->_left; } else if (key > node->_key) { parent = node; node = node->_right; } else { if (node->_left == nullptr) { if (parent == nullptr) _root = _root->_right; else { if (parent->_left == node) parent->_left = node->_right; else parent->_right = node->_right; } delete node; return true; } else if (node->_right == nullptr) { if (parent == nullptr) _root = _root->_left; else { if (parent->_left == node) parent->_left = node->_left; else parent->_right = node->_left; } delete node; return true; } else { //左右都不为空,找到左子树的最大节点或者右子树的最小节点 Node* maxleft = node->_left; Node* maxleftparent = node; while (maxleft->_right) { maxleftparent = maxleft; maxleft = maxleft->_right; } swap(node->_key, maxleft->_key); if (maxleftparent->_left == maxleft) maxleftparent->_left = maxleft->_left; else maxleftparent->_right = maxleft->_left; delete maxleft; return true; } } } return false; }

三,性能分析与退化问题

理想情况下,BST 高度 h≈log⁡2nh≈log2​n,查找、插入、删除时间复杂度均为 O(log⁡n)O(logn)。但如果插入序列本身有序(如1,2,3,4,5),BST 将退化为一根“向右的链表”,树高变为 nn,时间复杂度恶化为 O(n)O(n)。

这是基础 BST 的最大痛点。解决办法是使用 自平衡二叉搜索树,如:

1,AVL 树:严格平衡(左右子树高度差不超过 1),查找极快,但插入/删除旋转开销稍大。

2,红黑树:近似平衡(最长路径不超过最短路径的两倍),综合性能优异,是c++ std::map和std::set 的底层实现。

3,Treap、Splay 树:利用随机优先级或访问局部性进行平衡。

理解 BST 是进阶这些平衡树的前提。

四,总结

二叉搜索树将“二分查找”的思想扩展到了动态数据结构上,实现简单且功能强大。它让我们看到:仅仅通过维护“左小右大”这一简单的规则,就能高效组织、检索数据。而其退化的缺陷又顺理成章地引出了平衡树等数据结构。

http://www.jsqmd.com/news/1290225/

相关文章:

  • 2026年寄大件快递便宜全攻略:从同城到跨省都能用的低价技巧 - 快递物流资讯
  • 海导科技navynav|RTK定位设备:新一代AI语音RTK定位设备的测评
  • 千兆网口分立式 vs 集成式 RJ45:标准电路怎么接、料号怎么配
  • 如何在Windows 10/11上完美运行Android应用?WSABuilds一站式解决方案详解
  • 2026年江苏浮筒潜水搅拌机知名厂家:技术迭代中的明智之选 - 企业推荐官【官方】
  • 2026睢宁局部装修改造公司有哪些 靠谱服务商盘点 - 谁都没有我好看
  • Google Cloud Secret Manager + Cloud Run实战:密钥注入、轮换与审计日志
  • 抖店一件代发还可以做吗?新手商家必读,抖掌柜实操指南 - 抖掌柜
  • 别让 Data Agent 只会“给答案”:从 !assert 到 save,把分析变成可验证的生产数据资产
  • 【限时解密】某头部文旅平台内部使用的季节变换增强协议V2.3(含动态遮罩生成、多尺度时序一致性约束算法)
  • Siglec: 糖蛋白受体家族的免疫调节作用
  • 不下高速就入库:一家郑州仓储园区的侧面观察
  • Django-Vue3-Admin安全最佳实践:接口防护与数据加密策略
  • 【单片机课程设计/毕业设计】基于单片机的微型消毒箱监测与定时控制硬件系统设计 基于 STM32 的环境监测与消毒设备自动启停装置开发(011301)
  • 2026年托运电动车哪种托运最便宜?实测对比告诉你真相 - 快递物流资讯
  • AG Kit微服务集成案例:构建分布式AI Agent系统
  • one-page-website-html-css-project高级技巧:如何优化网站性能和用户体验
  • 2026年实力之选:靠谱的工地集装箱源头供应厂家与综合服务公司甄选 - 优企名品
  • 2026睢宁靠谱局部装修改造推荐 品质参考指南 - 谁都没有我好看
  • 探索跨平台Unity激活方案:UniHacker技术深度解析
  • N_m3u8DL-RE终极指南:跨平台流媒体下载神器从零到精通
  • 2026外墙工程金属百叶采购必看!湘潭通风铝合金百叶窗厂家/防雨锌钢空调外机罩格栅网怎么选?推荐锦锋诚雨湖岳塘湘乡韶山源头工厂!附基础分类特性百科介绍 - 奋斗者888
  • 深度揭秘:为什么大佬挖洞“又快又多”?普通人不知道的5个实战捷径
  • 2026年跨境电商真实复盘:我在TikTok Shop亏掉15万,含泪总结出这5条保命建议
  • RAG 正在裸奔:往知识库塞 5 篇文档,90% 的回答就被劫持了
  • 开题报告开挂✅3分钟出稿!AI搞定导师满意开题[特殊字符]
  • RRFPSBar核心原理揭秘:状态栏实时FPS绘制技术详解
  • ROS传感器数据准备指南:IMU、里程计与GPS消息格式与转换技巧
  • 2026年Q3江苏立式潜水搅拌机供应厂家——南京古蓝环保设备实业有限公司专业实力解析 - 企业推荐官【官方】
  • 一文读懂2026年国内十大SEO优化公司:服务特色、技术底座、行业适配与选型避坑指南全解读 - 品牌前沿专家