文章目录
一、基本概念
二叉搜索树:
- 空树
- 左子树都小于根,右子树都大于根,且左右子树也是二叉搜索树
二、重要性质
二叉搜索树的中序遍历结果是升序的
三、增删查改
1. 查找
cpp
bool find(const K& key)
{
node* cur = root_;
while(cur != nullptr)
{
if(key < cur->key_) cur = cur->left_;
else if(key > cur->key_) cur = cur->right_;
else return true;
}
return false;
}
2. 插入
cpp
bool insert(const K& key)
{
if(root_ == nullptr)
{
root_ = new node(key);
return true;
}
node* cur = root_;
node* parent = nullptr;
while(cur != nullptr)
{
parent = cur;
if(key < cur->key_) cur = cur->left_;
else if(key > cur->key_) cur = cur->right_;
else return false;
}
if(key < parent->key_) parent->left_ = new node(key);
else parent->right_ = new node(key);
return true;
}
3. 删除
记:要删除的结点为 d e l del del, d e l del del 的父节点为 p a r e n t parent parent
- d e l del del 左树为空
- d e l del del 是 p a r e n t parent parent 的 l e f t left left, p a r e n t parent parent 的 l e f t left left 指向 d e l del del 的右树
- d e l del del 是 p a r e n t parent parent 的 r i g h t right right, p a r e n t parent parent 的 r i g h t right right 指向 d e l del del 的右树
- d e l del del 是根节点, d e l del del 指向 d e l del del 的右树
- d e l del del 右树为空
- d e l del del 是 p a r e n t parent parent 的 l e f t left left, p a r e n t parent parent 的 l e f t left left 指向 d e l del del 的左树
- d e l del del 是 p a r e n t parent parent 的 r i g h t right right, p a r e n t parent parent 的 r i g h t right right 指向 d e l del del 的左树
- d e l del del 是根节点, d e l del del 指向 d e l del del 的左树
- d e l del del 左树右树都不为空
- 找到 d e l del del 右树中的最左结点 t m p tmp tmp
- 交换 t m p tmp tmp 和 d e l del del 的值
- 删除 t m p tmp tmp
- 该方法被称为替换法,替换删除后仍满足 d e l del del 大于左树,小于右树
cpp
bool erase(const K& key)
{
node* del = root_;
node* parent = nullptr;
//find the node to delete
while(del != nullptr)
{
if(key < del->key_)
{
parent = del;
del = del->left_;
}
else if(key > del->key_)
{
parent = del;
del = del->right_;
}
else
{
if(del->left_ == nullptr)//(1)
{
if(del == root_)
{
root_ = del->right_;
}
else
{
if(del == parent->left_)
{
parent->left_ = del->right_;
}
else
{
parent->right_ = del->right_;
}
}
}
else if(del->right_ == nullptr)//(2)
{
if(del == root_)
{
root_ = del->left_;
}
else
{
if(del == parent->left_)
{
parent->left_ = del->left_;
}
else
{
parent->right_ = del->left_;
}
}
}
else//(3)
{
node* tmp = del->right_;
node* tmp_parent = del;
//find the leftest node tmp of the right subtree
while(tmp->left_ != nullptr)
{
tmp_parent = tmp;
tmp = tmp->left_;
}
swap(tmp->key_, del->key_);
//delete tmp
//tmp has no left child
if(tmp == tmp_parent->left_)
{
tmp_parent->left_ = tmp->right_;
}
else
{
tmp_parent->right_ = tmp->right_;
}
del = tmp;
}
break;
}
}
if(del->key_ == key)
{
delete del;
return true;
}
else
{
return false;
}
}
四、性能分析
二叉搜索树的核心操作就是查找。
插入前需要查找应该插入的位置,替换法删除也需要查找被替换结点。
因此二叉搜索树的性能主要取决于查找的效率。
一般情况下,查找操作的时间复杂度是 O ( l o g n ) O(logn) O(logn)。
当插入序列是一个有序序列时,二叉搜索树会退化成单支树,效率退化成 O ( n ) O(n) O(n)。
如何改进:AVL 树、红黑树