BST:查找
看完你能写出BST查找的递归与迭代版本,并分析其复杂度边界
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
BST:查找
看完你能写出BST查找的递归与迭代版本,并分析其复杂度边界
BST的树结构
从根出发,每层比较一次决定走左或走右,箭头方向就是BST不变式给出的查找路径。
BST查找流程
从根节点出发,每层用key比较筛选方向,直到命中或落空。
查找的本质
在一个有序数组里找数字,每次和中间元素比较就能砍掉一半——这就是二分查找。但数组插入删除太慢,BST 把这个「砍半」的逻辑搬进了树结构里。
「大了/小了」每次砍掉一半可能,和树中走左/右是同一思路
递归查找分解
把"在BST里找一个值"拆解为层层缩小的递归调用,每一步都在严格缩小问题规模。
迭代查找分解
把递归的'调用栈'换成 while 循环,逐步展开迭代查找的执行路径。
查找实例演示
在一棵BST上演示查找12的完整路径:从根起,每步与当前节点比大小决定走向。
算法理解自测
关于BST查找的递归与迭代实现,以下哪项描述是正确的?
递归实现代码
把上一页的"分解"翻译成真实代码——递归查找的 Python 实现。
L3-L4 是两个停止口;L8、L11 是两次自我调用,分别把问题规模缩到左/右子树。
迭代实现代码
把递归的「向下递归」翻译成 while 循环,搜索路径完全一致,只是消掉了调用栈。
迭代版本用 cur 指针沿搜索路径下沉,三次比较对应「命中 / 走左 / 走右」三种状态,循环退出只有两种:命中 return cur,或路径到尽头 return None。
递归vs迭代对比
BST 查找两种写法都能正确,但性能和适用场景差异不小——选错可能导致栈溢出。
- 代码简洁,依赖系统调用栈
- 空间复杂度 O(h),h 为树高
- 适合树浅、面试或简洁优先
- 用 while + 变量循环,代码略长
- 空间复杂度 O(1),只用一个指针
- 适合树深、生产环境防栈溢出
复杂度深入分析
前面看了递归与迭代两种实现,现在问个根本问题:查找到底有多快?答案不在节点个数 n,而在树的高度 h——这个隐藏变量决定了 O(log n) 还是 O(n)。
有目录二分跳转对应 log n;目录撕了只能逐页翻对应 O(n)
边界情况处理
把查找算法丢进四种最极端的树形里跑一遍,看它会不会崩。
查找失败的语义
你去图书馆查一本书,管理员查完系统后说'没有'——这不是系统坏了,而是明确告诉你:这本书确实不在馆藏里。BST 查找返回 null,含义完全一样。
翻到末尾都没找到,说明字典里没收录这个字
树高与性能边界
上一页得到 BST 查找是 O(h),h 是树高。h 不是常数——同一组数据,插入顺序不同,h 可从 log n 涨到 n,效率差几个量级。
队尾总比前一个略高,要找某人只能从队头逐个数过去
BST查找小结
- ✓左小右大是结构承诺,搜索本质是一路剪枝
- ✓递归直观简洁,迭代无栈深风险更稳
- ✓时间复杂度O(h),h由树形而非数据量决定
- ✓终止顺序:先判null(区间空)后判等值(命中)
- ✓查找失败返回null是契约,由调用方判空
课后思考
先自己想,再看参考答案。这三个问题没有标准答案,重点是思考路径本身。
参考答案关键看树高。完全平衡时高度≈log n;若数据有序插入,树退化为链表,高度=n。树高决定比较次数。
参考答案按key定位节点,找到后返回value;删除也按key定位。要保证key仍满足BST有序性。这正是Map的简化模型。
参考答案经典做法是统一放右子树(或左),便于删除;若两侧都允许,查找可能命中多个,"找一个"和"找全部"语义会分裂。