一颗二叉搜索树可以为 空树 或者满足如下条件
对上述的二叉搜索树进行中序遍历的结果为: [1, 3, 4, 6, 7, 8, 10, 13, 14],因此二叉搜索树又称为二叉排序树
// 二叉搜索树结点
template<class K>
struct BSTreeNode
{
BSTreeNode<K>(const K& key = K())
: _key(key)
, _left(nullptr)
, _right(nullptr)
{}
K _key;
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
};
// 二叉搜索树
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
BSTree<K>()
: _root(nullptr)
{}
private:
Node* _root;
};
在二叉搜索树中,插入节点后仍需满足二叉搜索树的性质,如果插入的值在二叉搜索树中已经存在,则插入失败
时间复杂度 O(N): 因为二叉搜索树可能只有左子树或右子树
// 非递归版本
bool Insert(const K& key)
{
// 树为空时
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
// 为了找到插入位置后可以链接,需要保存父节点
Node* parent = nullptr;
Node* cur = _root;
// 找插入位置
while (cur)
{
// 保存父节点的位置
parent = cur;
// 当前结点值 大于 key 时,则插入位置在左子树
// 当前结点值 小于 key 时,则插入位置在右子树
// 当前结点值 等于 key 时,则插入失败
if (cur->_key > key) cur = cur->_left;
else if (cur->_key < key) cur = cur->_right;
else return false;
}
// 链接:判断插入位置在左子树还是右子树
cur = new Node(key);
if (parent->_key > key) parent->_left = cur;
else parent->_right = cur;
// 插入成功
return true;
}
// 递归版本
bool Insert(const K& key)
{
// 调用子函数递归
return _Insert(_root, key);
}
// 插入递归
static bool _Insert(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_key > key) return _Insert(root->_left, key);
else if (root->_key < key) return _Insert(root->_right, key);
else return false;
}
在二叉搜索树中,删除节点后仍需满足二叉搜索树的性质,将删除结点分四种情况
结点无左右孩子,可以直接删除
结点无左孩子,让父节点链接自己的右孩子后删除结点
结点无右孩子,让父节点链接自己的左孩子后删除结点
在结点无左孩子(或者无右孩子) 的情况中,如果删除的是根结点,则直接让根结点指针链接自己的右孩子(或者左孩子),然后删除结点
如果删除的值在二叉树中不存在,则删除失败
时间复杂度 O(N): 因为二叉搜索树可能只有左子树或右子树
// 非递归版本
bool Erase(const K& key)
{
// 树为空时,删除失败
if (_root == nullptr) return false;
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
// 保存父节点的位置
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
// 保存父节点的位置
parent = cur;
cur = cur->_right;
}
else
{
// 结点无左右孩子时,可以当作结点无左孩子处理
// 结点无左孩子时,父节点链接自己的右孩子,然后删除结点
// 结点无右孩子时,父节点链接自己的左孩子,然后删除结点
if (cur->_left == nullptr)
{
// 如果是根结点,根结点指针链接自己的右孩子
// 判断链接在父节点的左边还是右边
if (cur == _root) _root = cur->_right;
else if (parent->_key > key) parent->_left = cur->_right;
else parent->_right = cur->_right;
delete cur;
}
else if (cur->_right == nullptr)
{
// 如果是根结点,根结点指针链接自己的左孩子
// 判断链接在父节点的左边还是右边
if (cur == _root) _root = cur->_left;
else if (parent->_key > key) parent->_left = cur->_left;
else parent->_right = cur->_left;
delete cur;
}
else
{
// 找到左子树的最大结点
Node* maxLeftParent = cur;
Node* maxLeft = cur->_left;
while (maxLeft->_right)
{
maxLeftParent = maxLeft;
maxLeft = maxLeft->_right;
}
// 交换
std::swap(cur->_key, maxLeft->_key);
// 删除结点
if (maxLeftParent == cur) maxLeftParent->_left = maxLeft->_left;
else maxLeftParent->_right = maxLeft->_left;
delete maxLeft;
}
return true;
}
}
// 删除的值不存在
return false;
}
// 递归版本
bool Erase(const K& key)
{
return _Erase(_root, key);
}
static bool _Erase(Node*& root, const K& key)
{
if (root == nullptr) return false;
if (root->_key > key) return _Erase(root->_left, key);
else if (root->_key < key) return _Erase(root->_right, key);
else
{
Node* del = root;
if (root->_left == nullptr) root = root->_right;
else if (root->_right == nullptr) root = root->_left;
else
{
Node* minRightParent = root;
Node* minRight = root->_right;
while (minRight->_left)
{
minRightParent = minRight;
minRight = minRight->_left;
}
std::swap(root->_key, minRight->_key);
if (minRightParent == root) return _Erase(minRightParent->_right, key);
else return _Erase(minRightParent->_left, key);
}
delete del;
return true;
}
}
时间复杂度 O(N): 因为二叉搜索树可能只有左子树或右子树
// 非递归版本
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
// 当前结点值 大于 key 时,则 key 不可能在右子树
// 当前结点值 小于 key 时,则 key 不可能在左子树
// 当前结点值 等于 key 时,key 存在
if (cur->_key > key) cur = cur->_left;
else if (cur->_key < key) cur = cur->_right;
else return true;
}
// 不存在
return false;
}
// 递归版本
bool Find(const K& key)
{
return _Find(_root, key);
}
// 查找递归
static bool _Find(Node* root, const K& key)
{
if (root == nullptr) return false;
if (root->_key > key) return _Find(root->_left, key);
else if (root->_key < key) return _Find(root->_right, key);
else return true;
}
二叉搜索树的中序遍历:
void Inorder()
{
// 调用子函数递归
_Inorder(_root);
cout << endl;
}
// 中序递归
static void _Inorder(Node* root)
{
if (root == nullptr) return;
_Inorder(root->_left);
cout << root->_key << " ";
_Inorder(root->_right);
}
BSTree<K>(const BSTree<K>& bst)
: _root(nullptr)
{
_root = _BSTreeCopy(bst._root);
}
BSTree<K>& operator=(BSTree<K> bst)
{
std::swap(_root, bst._root);
return *this;
}
~BSTree<K>()
{
_BSTreeDestroy(_root);
_root = nullptr;
}
// 深拷贝递归
static Node* _BSTreeCopy(Node* root)
{
if (root == nullptr) return nullptr;
Node* rootCopy = new Node(root->_key);
rootCopy->_left = _BSTreeCopy(root->_left);
rootCopy->_right = _BSTreeCopy(root->_right);
return rootCopy;
}
// 销毁递归
static void _BSTreeDestroy(Node* root)
{
if (root == nullptr) return;
_BSTreeDestroy(root->_left);
_BSTreeDestroy(root->_right);
delete root;
}
K模型:结点只存储 key,用于快速查找 key 是否存在
判断单词 word 是否拼写错误:将词库中的所有单词作为 key 构建一颗二叉搜索树,在 K 模型中查找该单词,查找成功,则拼写正确,否则拼写错误
KV模型:结点存储
键值对,一个 key 值对应一个 value 值,用于通过 key 快速查找 value
英语翻译汉语:将词库中的所有单词及其翻译作为