0

0

c++中如何实现二叉搜索树的删除节点操作_c++树结构维护算法【详解】

尼克

尼克

发布时间:2026-01-18 09:54:08

|

796人浏览过

|

来源于php中文网

原创

BST删除节点需分三类处理:叶子节点直接删除并置空父指针;仅一子节点则用子节点顶替并修正父节点对应指针;两子节点须用中序后继替换值后递归删除后继,且后继可能带右子树需正确挂载。

c++中如何实现二叉搜索树的删除节点操作_c++树结构维护算法【详解】

删除节点时如何处理三种子节点情况

二叉搜索树(BST)删除节点的核心难点在于:被删节点的子节点数量不同,修复方式完全不同。不能只靠“找到就删”,必须按 node->left == nullptr && node->right == nullptrnode->left == nullptr || node->right == nullptrnode->left != nullptr && node->right != nullptr 三类分别处理。

常见错误是统一用中序后继替换却忘了更新后继的父指针,或在单子节点情况下直接用子节点覆盖却未修正其父节点的对应指针(比如该节点是父节点的左子还是右子没判断清楚)。

  • 叶子节点:直接 delete 并置空父节点对应指针
  • 仅一个子节点:用该子节点“顶替”被删节点位置,注意修改父节点的 leftright 指针
  • 两个子节点:必须用中序后继(右子树最左节点)或中序前驱(左子树最右节点)替换值,再递归删除那个后继/前驱节点——它必然是叶子或仅一子,否则逻辑不闭环

中序后继查找与链接断开的关键细节

选中序后继(而非前驱)是惯例,但实现时容易忽略:后继节点可能有右子树。此时不能直接把后继的右子树丢弃,而要将其挂到后继原父节点的左指针上(因为后继是“最左”,所以它一定是其父节点的左子)。

更隐蔽的问题是:若后继节点就是待删节点的右子(即右子树无左分支),那么后继的父节点就是待删节点本身,此时直接用 node->right 替换即可,无需额外断链。

立即学习C++免费学习笔记(深入)”;

TreeNode* findSuccessor(TreeNode* root) {
    root = root->right;
    while (root->left != nullptr) {
        root = root->left;
    }
    return root;
}

TreeNode deleteNode(TreeNode root, int key) { if (!root) return nullptr; if (key < root->val) { root->left = deleteNode(root->left, key); } else if (key > root->val) { root->right = deleteNode(root->right, key); } else { if (!root->left && !root->right) { delete root; return nullptr; } else if (!root->left) { TreeNode tmp = root->right; delete root; return tmp; } else if (!root->right) { TreeNode tmp = root->left; delete root; return tmp; } else { TreeNode* succ = findSuccessor(root); root->val = succ->val; // 关键:递归删除 succ,不是 root->right = succ->right root->right = deleteNode(root->right, succ->val); } } return root; }

递归实现中为什么必须返回 TreeNode*

因为 C++ 中函数参数默认传值,TreeNode* root 是指针的副本,修改形参本身(如 root = nullptr)不影响调用方的指针。只有通过返回新根并由上层赋值,才能真正切断旧连接。

PhotoG
PhotoG

PhotoG是全球首个内容营销端对端智能体

下载

典型反例:有人写 if (isLeaf) { delete root; root = nullptr; },这只会让函数内局部变量 root 变成空,上层调用处的指针仍指向已释放内存,后续访问必然崩溃。

  • 每次递归调用都必须接收返回值:root->left = deleteNode(root->left, key)
  • 叶子节点删除后必须返回 nullptr,否则父节点的 left/right 仍指向已释放地址
  • 单子节点场景下,返回子节点指针,相当于“把子节点提到当前位”,同时自动解绑原父子关系

非递归删除的指针维护陷阱

手动维护父指针的迭代写法看似直观,但极易出错:需同时追踪 currentparent,且必须在每步移动前记录谁是父节点。尤其当删除的是根节点时,parentnullptr,所有指针修正逻辑都要分支处理。

更大的坑在于:找到后继后,要从后继的父节点“摘下”它。如果后继就是 current->right,那它的父节点是 current;否则父节点在右子树中,得重新查找——这会让代码膨胀且难验证。

除非有明确性能约束(如空间极度受限),否则递归更安全。迭代版本唯一优势是可避免最坏 O(h) 栈深度,但实际 BST 若不平衡,h 可能接近 n,此时先做平衡化(如转 AVL)比硬写迭代删除更治本。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

746

2023.08.22

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

391

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

572

2023.08.10

数据库Delete用法
数据库Delete用法

数据库Delete用法:1、删除单条记录;2、删除多条记录;3、删除所有记录;4、删除特定条件的记录。更多关于数据库Delete的内容,大家可以访问下面的文章。

269

2023.11.13

drop和delete的区别
drop和delete的区别

drop和delete的区别:1、功能与用途;2、操作对象;3、可逆性;4、空间释放;5、执行速度与效率;6、与其他命令的交互;7、影响的持久性;8、语法和执行;9、触发器与约束;10、事务处理。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2023.12.29

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

402

2023.08.14

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

42

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

74

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

23

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.7万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 18.9万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号