BSTree的定义
struct BSTreeNode {
BSTreeNode<K> *_left;
BSTreeNode<K> *_right;
K _key;
BSTreeNode(const K &key)
: _left(nullptr), _right(nullptr), _key(key) {}
};
class BSTree {
typedef BSTreeNode<K> Node;
public:
private:
Node *_root = nullptr;
};
和普通二叉树一样的数据结构,只不过二叉搜索树是有序的,即左子树节点的key值都比根节点key值小,右子树节点的key值都比根节点大,且以下所有子树的节点都依照这个规律,形成二叉搜索树
注意:二叉搜索树中没有重复的节点key值,即每个节点的值都是独一无二的。
中序遍历这棵树即是升序:1 2 3 4 5 6 7 8 9 10
插入新节点
bool Insert(const K &key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node *parent = nullptr;
Node *cur = _root;
while (cur)
{
if (key > cur->_key)//插入值大于key时,往右走
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)//插入值小于key时,往左走
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);//新建插入值节点
// 链接
if (key > parent->_key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
插入和普通二叉树的区别就是,它需要找到key值的合适位置来插入,当插入值大于节点值时,往节点右边走,插入值小于节点值时,往节点左边走,当插入值不大于且不小于时,不插入,因为二叉搜索树中的节点值不能有重复值。
找到合适位置后,创建新节点并链接到目标节点的左或右,大于目标节点链接右边,小于链接左边。
删除节点
删除节点要考虑三种不同的情况:
bool Erase(const K &key)
{
Node* parent = _root;
Node* cur = _root;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
// 删除
// 1、左为空
if (cur->_left == nullptr)
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
delete cur;
} // 2、右为空
else if (cur->_right == nullptr)
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
else
{
// 找右树最小节点替代,也可以是左树最大节点替代
Node* prev=cur;
Node* minRight=cur->_right;
while(minRight->_left)
{
prev=minRight;
minRight=minRight->_left;
}
swap(cur->_key,minRight->_key);
if(prev->_left==minRight)
{
prev->_left=minRight->_right;
}
else
{
prev->_right=minRight->_right;
}
delete minRight;
}
return true;
}
}
return false;
}
1、叶子节点 (节点9)
parent的右边是需要删除的节点,那么直接链接cur的右边,即nullptr。
2、左右其中一个为空,另一个不为空 (节点8或节点2)
节点8:目标节点cur左边为空,如果cur在parent右边,那么就把cur的右节点“托孤”给parent的右边
节点2:目标节点cur右边为空,如果cur在patent左边,那么就把cur的左节点”托孤“给parent的左边
托孤完成后delete目标节点cur即可。
3、左右都不为空
找到要删除的节点cur后,找它右子树最小的节点,让右子树最小的节点来代替它的位置。
先交换key值,如果prev右边是最小节点,那么让最小节点的右边继承给prev右边。
如果prev左边边是最小节点,那么让最小节点的右边继承给prev左边。