目录
什么是二叉搜索树?
二叉搜索树又称二叉排序树 ,它或是一棵空树,或是具有以下性质的二叉树:
- 每个节点都有一个键值(key),且所有键值互不相同(也可以允许重复,但一般定义不重复)
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树

二叉树基本操作
下面通过给定二叉树演示二叉树基本操作
cpp
int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};
8
/ \
3 10
/ \ \
1 6 14
/ \ /
4 7 13
二叉搜索树的查找
从根节点开始:
- 若目标值等于当前节点值,找到。
- 若目标值小于当前节点值,进入左子树。
- 若目标值大于当前节点值,进入右子树。
最多查找高度次,走到到空,还没找到,这个值不存在
时间复杂度:
- 平均:𝑂(log𝑛)(如果树比较平衡)
- 最坏:𝑂(𝑛)(退化成链表,比如插入有序数据时)
二叉搜索树的插入
插入的具体过程如下:
- 树为空,则直接新增节点,赋值给root指针
- 树不空,按二叉搜索树性质查找插入位置,插入新节点
时间复杂度和查找相同

二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面三种情 况:
无子节点:直接删除。
有一个子节点:用其子节点代替自己。
有两个子节点 :
通常用 左子树的最大值节点 或 右子树的最小值节点 的值替换当前节点值。
再删除那个被借值的节点(该节点最多有一个子节点)
注:
使用右子树的最小值节点:
最小值节点不可能有左子节点(如果有更小的值,它就不是最小值了)
它可能有右子节点(右子节点的值都大于它)
使用左子树的最大值节点:
最大值节点不可能有右子节点(如果有更大的值,它就不是最大值了)
它可能有左子节点(左子节点的值都小于它)

二叉搜索树的遍历
中序遍历(左 → 根 → 右)会得到 升序序列
二叉搜索树的实现
cpp
// 二叉树节点
template<class K, class V>
class BSTreeNode {
public:
pair<K, V> _kv;
BSTreeNode* _left;
BSTreeNode* _right;
BSTreeNode(const K& key, const V& value)
:_kv(make_pair(key,value)),_left(nullptr),_right(nullptr)
{}
};
//二叉搜索树
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
public:
// 插入节点
bool Insert(const K& key, const V& value) {
if (_root == nullptr) {
_root = new Node(key, value);
return true;
}
else {
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
if (cur->_kv.first > key) {
parent = cur;
cur = cur->_left;
}
else if (cur->_kv.first < key) {
parent = cur;
cur = cur->_right;
}
else {
// 键已存在,更新值
cur->_kv.second = value;
return false;
}
}
cur = new Node(key, value);
if (key < parent->_kv.first)
parent->_left = cur;
else
parent->_right = cur;
return true;
}
}
// 查找节点
Node* Find(const K& key) {
Node* cur = _root;
while (cur) {
if (key < cur->_kv.first) {
cur = cur->_left;
}
else if (key > cur->_kv.first) {
cur = cur->_right;
}
else {
return cur;
}
}
return nullptr;
}
// 删除节点
bool Erase(const K& key) {
Node* parent = nullptr;
Node* cur = _root;
// 查找要删除的节点
while (cur) {
if (key < cur->_kv.first) {
parent = cur;
cur = cur->_left;
}
else if (key > cur->_kv.first) {
parent = cur;
cur = cur->_right;
}
else {
// 找到要删除的节点
// 情况1:没有左子节点
if (cur->_left == nullptr) {
if (cur == _root) {
_root = cur->_right;
}
else {
if (parent->_left == cur) {
parent->_left = cur->_right;
}
else {
parent->_right = cur->_right;
}
}
delete cur;
}
// 情况2:没有右子节点
else if (cur->_right == nullptr) {
if (cur == _root) {
_root = cur->_left;
}
else {
if (parent->_left == cur) {
parent->_left = cur->_left;
}
else {
parent->_right = cur->_left;
}
}
delete cur;
}
// 情况3:有两个子节点
else {
// 找右子树的最小节点(或左子树的最大节点)
Node* minParent = cur;
Node* minRight = cur->_right;
while (minRight->_left) {
minParent = minRight;
minRight = minRight->_left;
}
// 替换值
cur->_kv = minRight->_kv;
// 删除minRight
if (minParent->_left == minRight) {
minParent->_left = minRight->_right;
}
else {
minParent->_right = minRight->_right;
}
//这个if-else判断是为了正确处理minRight是其父节点的左孩子还是右孩子的不同情况
delete minRight;
}
return true;
}
}
return false; // 没找到
}
void _InOrder(Node* root) {
if (root == nullptr) return;
_InOrder(root->_left);
cout << "(" << root->_kv.first << ", " << root->_kv.second << ") ";
_InOrder(root->_right);
}
void InOrder() {
_InOrder(_root);
cout << endl;
}
private:
Node* _root = nullptr;
};