二叉搜索树又称二叉排序树,他对数据有严格的要求,具体表现在以下几个方面:
二叉搜索树的实际应用主要分为K模型和KV模型。
由于是KV模型,我们需要存储Key和Value俩个值。同时二叉搜索树也是二叉树,我们需要它的左右节点。因此节点疯转如下:
template<class K, class V>
struct BSTreeNode
{
K _key;
V _value;
BSTreeNode<K, V>* _left;
BSTreeNode<K, V>* _right;
//默认构造函数, 用于后续new创建节点
BSTreeNode(const K& key, const V& value)
:_key(key)
, _value(value)
, _right(nullptr)
, _left(nullptr)
{}
};
接下来是KV模型封装的框架,以及默认构造、拷贝构造、赋值重载、析构函数。比较简单,就直接给出代码了哈。
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;//节点重命名
public:
//默认构造
BSTree()
:_root(nullptr)
{}
//拷贝构造
BSTree(BSTree<K, V>& t)
{
_root = Copy(t._root);
}
//赋值重载
BSTree<K, V>& operator=(BSTree<K, V> t)
{
swap(_root, t._root);
return *this;
}
//析构函数
~BSTree()
{
Destory(_root);
}
private:
Node* _root = nullptr;
};
}
首先我们需要查找数据待插入的位置(为了保证插入数据后整体依然是一颗二叉搜索树).。同时查找插入位置时,只有key是有严格要求的,Value只是附带。
即:如果根节点为空,即是待插入数据位置;否则开始查找,如果待插入数据大于根节点往右子树节点走;如果待插入数据小于根节点往左子树节点走。不断循环,直到查找到空节点时,即为数据待插入的位置;如果查找到的大小和待插入数据值相等则返回false(确保二叉搜索树中的每个节点唯一)
【非递归版本】:
bool Insert(const K& key, const V& value)
{
if (_root == nullptr)//根节点为空
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = nullptr;//后续插入数据链接时,需要和父节点相连
while (cur)
{
if (cur->_key > key)//待插入数据小于当前节点,往左子树查找
{
parent = cur;
cur = cur->_left;
}
else if(cur->_key < key)//待插入数据大于当前节点,往右子树查找
{
parent = cur;
cur = cur->_right;
}
else//待插入数据等于当前节点,不允许插入
{
return false;
}
}
//链接
Node* newNode = new Node(key, value);
//链接时,我们无法确定插入节点时在父节点的左边还是右边,需要进一步比较
if (parent->_key > key)
parent->_left = newNode;
else
parent->_right = newNode;
return true;
}
【递归版本】:
bool InsertR(const K& key, const V& value)
{
//由于我们查找位置需要从根节点开始查找,所以这里通过另一个函数来传递实现
return _InsertR(_root, key, value);
}
bool _InsertR(Node*& root, const K& key, const V& value)
{
if (root == nullptr)
{
//注意上述我们形参都是引用,所以不用新增Parent节点
root = new Node(key, value);
return true;
}
if (root->_key > key)//待插入数据小于当前节点,往左子树查找
return _InsertR(root->_left, key, value);
else if (root->_key < key)//待插入数据大于当前节点,往右子树查找
return _InsertR(root->_right, key, value);
else
return false;
}
删除数据,我们首先需要和插入数据一样,先查找到待删除节点。和插入类似就不多说了。
【查找待删除数据】:
bool Erase(const K& key)
{
if (_root == nullptr)//为空即不存在待删除数据
return false;
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key > key)//待删除数据小于当前节点,往左子树查找
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)//待删除数据大于当前节点,往右子树查找
{
parent = cur;
cur = cur->_right;
}
else
{
//当前位置即为待删除节点,装备删除数据
}
}
return false;//整棵树中不存在待删除数据
}
插找到待删除数据后,显然如果只是简单将该节点删除,有可能将不满足二叉搜索树的要求,那怎么办呢?
删除数据分为以下三种情况:
左子树为空主要分为以下情形:右子树为空,左子树不为空;左右子树均为空(省略)。
不管上述那种情况,我们发现只需将父节点的下一个节点指向待删除节点的右指针即可。但需要注意的是,如果待删除节点为根节点,它将没有父节点,需要单独处理。
【代码实现】:
if (cur->_left == nullptr)//左子树为空
{
if (parent == _root)//cur为根节点
{
_root = cur->_right;
}
else
{
if (parent->_key > cur->_key)//待删除节点在父节点左子树中
{
parent->_left = cur->_right;
}
else//待删除节点在父节点右子树中
{
parent->_right = cur->_right;
}
}
delete cur;
}
右子树为空分为单纯右子树为空和左右子树均为空(省)。具体处理方式和左子树为空类似就不多说了。
【代码实现】:
//左右子树均不为空,查找右子树最小元素进行交换后删除
if (parent == _root)//cur为根节点
{
_root = cur->_left;
}
else
{
if (parent->_key > cur->_key)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
这种情况我们可以查找左子树最大值或右子树最小值和待删除删除节点进行交换,交换后我们可以转化为上述两种子问题来删除数据。(接下来博主以交换右子树最小值为例)
Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
parent = cur;
subLeft = subLeft->_left;
}
//交换
swap(cur->_key, subLeft->_key);
swap(cur->_value, subLeft->_value);
//删除
if (parent->_right = subLeft)
{
parent->_right = subLeft->_right;
}
else
{
parent->_left = subLeft->_right;
}
delete subLeft;
递归思路和非递归差球不多,就不一一分析了,下面直接给出两种实现方式代码。
【非递归版本】:
bool Erase(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = nullptr;
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 (parent == _root)//cur为根节点
{
_root = cur->_right;
}
else
{
if (parent->_key > cur->_key)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)//右子树为空
{
if (parent == _root)//cur为根节点
{
_root = cur->_left;
}
else
{
if (parent->_key > cur->_key)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{//左右子树均不为空,查找右子树最小元素进行交换后删除
Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
parent = cur;
subLeft = subLeft->_left;
}
//交换
swap(cur->_key, subLeft->_key);
swap(cur->_value, subLeft->_value);
//删除
if (parent->_right = subLeft)
{
parent->_right = subLeft->_right;
}
else
{
parent->_left = subLeft->_right;
}
delete subLeft;
}
return true;
}
}
return false;
}
【递归版本】:
//删除:递归版本
bool EraseR(const K& key)
{
return _EraseR(_root, key);//同理,由于需要根节点,在通过一层函数来实现
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)//非找到
return false;
if (root->_key > key)//转化成递归子问题,在左子树中删除key
return _EraseR(root->_left, key);
else if (root->_key < key)//转化成递归子问题,在右子树中删除key
return _EraseR(root->_right, key);
else
{//删除数据
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
return true;
}
else if (_root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
return true;
}
else
{
Node* subLeft = root->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
//交换
swap(root->_key, subLeft->_key);
swap(root->_value, subLeft->_value);
return _EraseR(root->_right, key);
}
}
}
【递归版本】:
//查找:递归版本
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
Node* _FindR(Node*& root, const K& key)
{
if (root == nullptr)
return nullptr;
if (root->_key > key)
return _FindR(root->_left, key);
else if (root->_key < key)
return _FindR(root->_right, key);
else
return root;
}
【非递归版本】:
//查找:非递归版本
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
cur = cur->_left;
else if (cur->_key < key)
cur = cur->_right;
else
{//找到了
return cur;
}
}
return nullptr;
}
//中序遍历
void Inorder()
{
_Inorder(_root);
cout << endl;
}
void _Inorder(Node* root)
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_key << "->" << root->_value << " " << endl;
_Inorder(root->_right);
}
gitee:所有代码及测试代码
namespace KeyValue
{
template<class K, class V>
struct BSTreeNode
{
K _key;
V _value;
BSTreeNode<K, V>* _left;
BSTreeNode<K, V>* _right;
//默认构造函数
BSTreeNode(const K& key, const V& value)
:_key(key)
, _value(value)
, _right(nullptr)
, _left(nullptr)
{}
};
template<class K, class V>
class BSTree
{
typedef BSTreeNode<K, V> Node;
public:
//
//默认构造
BSTree()
:_root(nullptr)
{}
//拷贝构造
BSTree(BSTree<K, V>& t)
{
_root = Copy(t._root);
}
//赋值重载
BSTree<K, V>& operator=(BSTree<K, V> t)
{
swap(_root, t._root);
return *this;
}
//析构函数
~BSTree()
{
Destory(_root);
}
//
//插入, 非递归版本
bool Insert(const K& key, const V& value)
{
if (_root == nullptr)
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if(cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
//链接
Node* newNode = new Node(key, value);
if (parent->_key > key)
parent->_left = newNode;
else
parent->_right = newNode;
return true;
}
// 插入: 递归遍布
bool InsertR(const K& key, const V& value)
{
return _InsertR(_root, key, value);
}
/
//查找:非递归版本
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
cur = cur->_left;
else if (cur->_key < key)
cur = cur->_right;
else
{//找到了
return cur;
}
}
return nullptr;
}
//查找:递归版本
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
/
//删除:非递归版本
bool Erase(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = nullptr;
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 (parent == _root)//cur为根节点
{
_root = cur->_right;
}
else
{
if (parent->_key > cur->_key)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)//右子树为空
{
if (parent == _root)//cur为根节点
{
_root = cur->_left;
}
else
{
if (parent->_key > cur->_key)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{//左右子树均不为空,查找右子树最小元素进行交换后删除
Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
parent = cur;
subLeft = subLeft->_left;
}
//交换
swap(cur->_key, subLeft->_key);
swap(cur->_value, subLeft->_value);
//删除
if (parent->_right = subLeft)
{
parent->_right = subLeft->_right;
}
else
{
parent->_left = subLeft->_right;
}
delete subLeft;
}
return true;
}
}
return false;
}
//删除:递归版本
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
/
//中序遍历
void Inorder()
{
_Inorder(_root);
cout << endl;
}
void _Inorder(Node* root)
{
if (root == nullptr)
return;
_Inorder(root->_left);
cout << root->_key << "->" << root->_value << " " << endl;
_Inorder(root->_right);
}
private:
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;
}
void Destory(Node*& root)
{
if (root == nullptr)
return;
Destory(root->_right);
Destory(root->_left);
delete root;
root = nullptr;
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key > key)
return _EraseR(root->_left, key);
else if (root->_key < key)
return _EraseR(root->_right, key);
else
{//删除数据
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
return true;
}
else if (_root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
return true;
}
else
{
Node* subLeft = root->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
//交换
swap(root->_key, subLeft->_key);
swap(root->_value, subLeft->_value);
return _EraseR(root->_right, key);
}
}
}
bool _InsertR(Node*& root, const K& key, const V& value)
{
if (root == nullptr)
{
root = new Node(key, value);
return true;
}
if (root->_key > key)
return _InsertR(root->_left, key, value);
else if (root->_key < key)
return _InsertR(root->_right, key, value);
else
return false;
}
Node* _FindR(Node*& root, const K& key)
{
if (root == nullptr)
return nullptr;
if (root->_key > key)
return _FindR(root->_left, key);
else if (root->_key < key)
return _FindR(root->_right, key);
else
return root;
}
Node* _root = nullptr;
};
}