单纯的二叉树,并不能体现出优秀的存储和查找能力,但是对二叉树附加一些规则,
就能让二叉树成为很高效的存储和查找的一种数据结构,所以今天会介绍,基于二
叉树和一些附加规则的树——搜索二叉树
1.搜索二叉树
搜索二叉树的规则也很简单,就是左节点要比根大,右节点比根大。
2. 搜索树的特点
1.中序遍历时得到的序列是有序序列
2.不支持有重复元素
3.查找效率是O(N),当树是满二叉树或者完全二叉树时,效率达到logN级别。
4.不支持修改,只有增删查
3. 搜索二叉树的实现
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_key > key) cur = cur->_left;
else if (cur->_key < key) cur = cur->_right;
else return false;
}
if (parent->_key > key) parent->_left = new Node(key);
else if (parent->_key < key) parent->_right = new Node(key);
return true;
}
bool 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 true;
}
return false;
}
bool Erase(const K& key)
{
Node* parent = _root;
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
{
Node* deNode = cur;
if (deNode->_right == nullptr)
{
if (deNode->_key > parent->_key) parent->_right = deNode->_left;
else if (deNode->_key < parent->_key) parent->_left = deNode->_left;
else _root = cur->_left;
}
else if (deNode->_left == nullptr)
{
if (deNode->_key > parent->_key) parent->_right = deNode->_right;
else if (deNode->_key < parent->_key) parent->_left = deNode->_right;
else _root = cur->_right;
}
else
{
Node* subNode = deNode->_left;
Node* par_subNode = deNode;
while (subNode->_right) par_subNode = subNode, subNode = subNode->_right;
swap(subNode->_key, deNode->_key);
deNode = subNode;
if (par_subNode->_left == deNode) par_subNode->_left = nullptr;
if (par_subNode->_right == deNode) par_subNode->_right = nullptr;
}
delete deNode;
return true;
}
}
return false;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
private:
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
Node* _root = nullptr;
};
搜索二叉树实现的细节
搜索二叉树的实现难点主要在删除。删除时我们需要考虑很多因素
比如删除叶子节点,只有左/右子树的节点,删除左右子树都在的节点。
a. 删除只有左/右子树的节点
删除叶子节点可以归类到这两个中的任意一个,不单独说了。
我们假如要删除26,采用的方法是将它右子树的根给它的父亲节点即可,同理删除之有左子树的时候,也仅需把左子树的根给父亲节点即可
需要注意的是,给父亲节点时需要判断被删的节点是他父亲节点的左还是右节点。
删除节点是根的情况,第三个分支就是解决删除节点是根的情况,将左/右子树的根重新换成整棵树的根即可
b. 删除两子树都在的节点
采用的方法是替换法:将被删节点与它左子树的最大值或者右子树的最小值交换,
交换之后,只需要删除,交换后的叶子节点即可
左子树的最右边是左子树的最大值,右子树的最左边是右子树的最小值
左子树的最大值或者右子树的最小值必是叶子节点
交换之后,这棵树仍然是搜索二叉树