深度剖析二叉搜索树(BST)
一、核心定义
二叉搜索树 Binary Search Tree,简称 BST满足左小右大严格规则的二叉树:
- 左子树所有节点值 < 根节点值
- 右子树所有节点值 > 根节点值
- 左右子树也必须是二叉搜索树
- 无重复节点(默认规则)
二、五大核心性质
- 中序遍历 = 升序有序序列(BST 最关键特性)
- 最小值:一路向左走到最左叶子
- 最大值:一路向右走到最右叶子
- 前驱节点:比当前节点小的最大节点
- 后继节点:比当前节点大的最小节点
三、四大基础操作(原理 + 流程)
1. 查找节点
逻辑:比根小走左,比根大走右,相等找到
- 时间复杂度:O(h) h = 树高
- 最优 O (logn)
- 最坏 O (n)(斜树)
2. 插入节点
- 从根开始比较
- 小于根走左,大于走右
- 走到空位置直接挂载
- 不改变原有树结构
3. 删除节点**(最难!分 3 种情况)**
情况 1:删除叶子节点
直接置空,无任何影响
情况 2:删除只有一个子树节点
用唯一子节点顶替被删节点
情况 3:删除左右都有子树节点(核心)
两种方案二选一
- 找右子树最小值替换,删除该最小值
- 找左子树最大值替换,删除该最大值目的:保留 BST 有序性
4. 遍历
- 前序:根→左→右
- 中序:左→根→右 (升序)
- 后序:左→右→根
- 层序:从上到下逐层遍历
代码实现
1. 节点结构设计
template<class K> struct BSTNode { K _key; BSTNode<K>* _left; BSTNode<K>* _right; BSTNode(const K& key) :_key(key) ,_left(nullptr) ,_right(nullptr) { } };
2. 二叉搜索树类
template<class K> class BSTree { typedef BSTNode<K> Node; private: Node* _root = nullptr; };
3. 核心功能解析
1️⃣ 插入(Insert)
bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { //查找是否有相同的值,判断是否插入 if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(key); if (parent->_key < key) { parent->_right = cur; } else { parent->_left = cur; } return true; }思想:
若树为空,直接作为根节点
否则从根开始比较:
小 → 往左走
大 → 往右走
相等 → 插入失败(不允许重复)
2️⃣ 查找(Find)
bool Find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) { cur = cur->_right; } else if (cur->_key > key) { cur = cur->_left; } else { return true; } } return false; }
3️⃣ 删除(Erase)------最复杂的部分
✅ 情况一:左子树为空
cppif (cur->_left == nullptr) { if (cur != _root) { // 左为空,父亲指向我的右 if (cur == parent->_left) { parent->_left = cur->_right; } else { parent->_right = cur->_right; } } else { _root = cur->_right; } delete cur; return true; }**✅**情况二:右子树为空
cppelse if (cur->_right == nullptr) { if (cur != _root) { // 右为空,父亲指向我的左 if (cur == parent->_left) { parent->_left = cur->_left; } else { parent->_right = cur->_left; } } else { _root = cur->_left; } delete cur; return true; }**✅**情况三:左右子树都不为空(重点)
**策略:**替换删除法
找到右子树中的最小节点(最左节点)
用该节点的值替换待删除节点
删除那个最小节点
cppelse { Node* minRightParent = cur;//为什么这里不置空?思考下 Node* minRight = cur->_right; while (minRight->_left) { minRightParent = minRight; minRight = minRight->_left; } swap(cur->_key, minRight->_key); if (minRight == minRightParent->_left) minRightParent->_left = minRight->_right; else minRightParent->_right = minRight->_right; delete minRight; return true; }
✅完整代码
cppbool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { if (cur->_left == nullptr) { if (cur != _root) { // 左为空,父亲指向我的右 if (cur == parent->_left) { parent->_left = cur->_right; } else { parent->_right = cur->_right; } } else { _root = cur->_right; } delete cur; } else if (cur->_right == nullptr) { if (cur != _root) { // 右为空,父亲指向我的左 if (cur == parent->_left) { parent->_left = cur->_left; } else { parent->_right = cur->_left; } } else { _root = cur->_left; } delete cur; } else { Node* minRightParent = cur; Node* minRight = cur->_right; while (minRight->_left) { minRightParent = minRight; minRight = minRight->_left; } swap(cur->_key, minRight->_key); if (minRight == minRightParent->_left) minRightParent->_left = minRight->_right; else minRightParent->_right = minRight->_right; delete minRight; } return true; } } return false; }
4️⃣ 中序遍历(InOrder)
cpppublic: void InOrder() { _InOrder(_root); cout << endl; } private: void _InOrder(Node* root) { if (root == nullptr) return; _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); }
- 将遍历功能分为公有对外接口函数与私有递归辅助函数
- 对外
InOrder()无参数,作为调用入口- 私有
_InOrder(Node*)接收当前节点,实现递归遍历逻辑- 外部调用公有接口,接口内部自动传入根节点调用递归函数
- 有效隐藏树节点指针,符合 C++ 类封装设计思想
完整代码
cpp#pragma once #include <iostream> using namespace std; namespace key { template<class K> struct BSTNode { K _key; BSTNode<K>* _left; BSTNode<K>* _right; BSTNode(const K& key) :_key(key), _left(nullptr), _right(nullptr) { } }; template<class K> class BSTree { using Node = BSTNode<K>; public: BSTree() = default; BSTree(const BSTree& t) { _root = Copy(t._root); } BSTree& operator=(BSTree tmp) { swap(_root, tmp._root); return *this; } ~BSTree() { Destroy(_root); _root = nullptr; } bool Insert(const K& key) { if (_root == nullptr) { _root = new Node(key); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(key); if (parent->_key < key) parent->_right = cur; else parent->_left = cur; return true; } bool find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) cur = cur->_right; else if (cur->_key > key) cur = cur->_left; else return true; } return false; } bool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { if (cur->_left == nullptr) { if (parent == nullptr) _root = cur->_right; else { if (parent->_left == cur) parent->_left = cur->_right; else parent->_right = cur->_right; } delete cur; return true; } else if (cur->_right == nullptr) { if (parent == nullptr) _root = cur->_left; else { if (parent->_left == cur) parent->_left = cur->_left; else parent->_right = cur->_left; } delete cur; return true; } else { Node* replaceParent = cur; Node* replace = cur->_right; while (replace->_left) { replaceParent = replace; replace = replace->_left; } cur->_key = replace->_key; if (replaceParent->_left == replace) replaceParent->_left = replace->_right; else replaceParent->_right = replace->_right; delete replace; return true; } } } return false; } void Inorder() { _Inorder(_root); cout << endl; } private: void _Inorder(Node* root) { if (root == nullptr) return; _Inorder(root->_left); cout << root->_key << " "; _Inorder(root->_right); } void Destroy(Node* root) { if (root == nullptr) return; Destroy(root->_left); Destroy(root->_right); delete root; } Node* Copy(Node* root) { if (root == nullptr) return nullptr; Node* newRoot = new Node(root->_key); newRoot->_left = Copy(root->_left); newRoot->_right = Copy(root->_right); return newRoot; } Node* _root = nullptr; }; }
⼆叉搜索树key和key/value使⽤场景
类型 排序依据 存储内容 典型用途 纯 key key 本身 仅关键字 查重、排序、元素判定 key-value key 字段 关键字 + 业务数据 映射查找、数据索引 场景 1:简易中英互译词典
场景 2:统计水果出现次数
完整代码
cppnamespace key_value { template<class K, class V> struct BSTNode { K _key; V _value; BSTNode<K, V>* _left; BSTNode<K, V>* _right; BSTNode(const K& key, const V& value) :_key(key), _value(value), _left(nullptr), _right(nullptr) {} }; template<class K, class V> class BSTree { using Node = BSTNode<K, V>; public: BSTree() = default; BSTree(const BSTree& t) { _root = Copy(t._root); } BSTree& operator=(BSTree tmp) { swap(_root, tmp._root); return *this; } ~BSTree() { Destroy(_root); _root = nullptr; } bool Insert(const K& key, const V& value) { if (_root == nullptr) { _root = new Node(key, value); return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { return false; } } cur = new Node(key, value); if (parent->_key < key) parent->_right = cur; else parent->_left = cur; return true; } Node* find(const K& key) { Node* cur = _root; while (cur) { if (cur->_key < key) cur = cur->_right; else if (cur->_key > key) cur = cur->_left; else return cur; } return nullptr; } bool Erase(const K& key) { Node* parent = nullptr; Node* cur = _root; while (cur) { if (cur->_key < key) { parent = cur; cur = cur->_right; } else if (cur->_key > key) { parent = cur; cur = cur->_left; } else { if (cur->_left == nullptr) { if (parent == nullptr) _root = cur->_right; else { if (parent->_left == cur) parent->_left = cur->_right; else parent->_right = cur->_right; } delete cur; return true; } else if (cur->_right == nullptr) { if (parent == nullptr) _root = cur->_left; else { if (parent->_left == cur) parent->_left = cur->_left; else parent->_right = cur->_left; } delete cur; return true; } else { Node* replaceParent = cur; Node* replace = cur->_right; while (replace->_left) { replaceParent = replace; replace = replace->_left; } cur->_key = replace->_key; cur->_value = replace->_value; if (replaceParent->_left == replace) replaceParent->_left = replace->_right; else replaceParent->_right = replace->_right; delete replace; return true; } } } return false; } void Inorder() { _Inorder(_root); cout << endl; } private: void _Inorder(Node* root) { if (root == nullptr) return; _Inorder(root->_left); cout << root->_key << ":" << root->_value << endl; _Inorder(root->_right); } void Destroy(Node* root) { if (root == nullptr) return; Destroy(root->_left); Destroy(root->_right); delete root; } Node* Copy(Node* root) { if (root == nullptr) return nullptr; Node* newRoot = new Node(root->_key, root->_value); newRoot->_left = Copy(root->_left); newRoot->_right = Copy(root->_right); return newRoot; } Node* _root = nullptr; }; }



