目录
概念
二叉搜索树的查找
代码实现
二叉搜索树的插入
代码实现
二叉搜索树的删除
代码实现
二叉搜索树的遍历
代码实现
完整代码
概念
二叉搜索树(BST)又称二叉排序树或二叉查找树,它可以是一颗空树,也可以是具有以下性质的二叉树:
举例:
PS:当该二叉搜索树为满二叉树(完全二叉树)时,为O(logN)。
//查找函数
Node* Find(const K& key) {
Node* cur = _root;
while (cur)
{
//查找数key比当前结点大,往右子树查找
if (cur->_key < key)
{
cur = cur->_right;
}
//查找数key比当前结点小,往左子树查找
else if (cur->_key > key)
{
cur = cur->_left;
}
//查找数key与当前结点相等,找到了
else
{
return cur;
}
}
//未找到
return nullptr;
}
插入的具体过程如下:
1.树为空,则直接新增节点,赋值给root指针
2.树不为空,按二叉搜索树性质查找适合的插入位置,插入新节点
//插入函数
bool Insert(const K& key, const V& value)
{
if (_root == nullptr)
{
_root = new Node(key,value);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
//要插入的key值比当前结点大,往右子树走,进行插入
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
//要插入的key值比当前结点小,往左子树走,进行插入
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
要插入的key值与当前结点值相等,插入失败
else
{
return false;
}
}
cur = new Node(key, value);
if (parent->_key > key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
首先先查找元素是否在二叉搜索树中,如果不存在,则返回,否则要删除的节点可能分为下面四种情况:
1.要删除的节点无孩子节点。
2.要删除的节点只有左孩子节点。
3.要删除的节点只有右孩子节点。
4.要删除的节点有左、右孩子节点。
上述情况可以分为两种处理方式,1、2、3为一种,4为一种。
情况2:删除节点且使被删除节点的父亲节点指向被删除节点的左孩子节点,然后直接删除。
情况3:删除节点且使被删除节点的父亲节点指向被删除节点的右孩子节点,然后直接删除。
情况4:查找删除点的左子树的最大节点(最右节点)或者右子树的最小节点(最左节点)与删除点进行替换,在处理该节点的删除问题
//删除
bool Erase(const K& key)
{
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 = _root->_right;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_right;
}
else
{
parent->_left = cur-> _right;
}
}
}
//要删除的结点右子树为空
else if (cur->_right == nullptr)
{
//要删除的结点是根结点
if (cur == _root)
{
_root = _root->_left;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_left;
}
else
{
parent->_left = cur->_left;
}
}
}
//要删除的结点左右子树都存在
else
{
//寻找替代结点
Node* parent = cur;
Node* rightMin = cur->_right;
while (rightMin->_left)
{
parent = rightMin;
rightMin = rightMin->_left;
}
//交换替代结点与要删除的结点的值
swap(cur->_key, rightMin->_key);
swap(cur->_val, rightMin->_val);
if (parent->_left == rightMin)
{
parent->_left = rightMin->_left;
}
else
{
parent->_right = rightMin->_left;
}
cur = rightMin;
}
delete cur;
return true;
}
}
}
如果按照中序遍历的话,就是从小到大遍历了。
//中序遍历函数
void _InOrder(Node* root) {
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
cout << root->_key << ' ';
_InOrder(root->_right);
}
#include
using namespace std;
template
//二叉搜索树结点封装
class BSTreeNode
{
public:
BSTreeNode* _left;
BSTreeNode* _right;
K _key;
V _value;
BSTreeNode(const K& key, const V& value)
:_left(nullptr)
, _right(nullptr)
, _key(key)
, _value(value)
{}
};
template
class BSTree
{
typedef BSTreeNode Node;
public:
//构造函数
BSTree()
:_root(nullptr)
{}
//插入函数
bool Insert(const K& key, const V& value)
{
if (_root == nullptr)
{
_root = new Node(key,value);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur) {
//要插入的key值比当前结点大,往右子树走,进行插入
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
//要插入的key值比当前结点小,往左子树走,进行插入
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
要插入的key值与当前结点值相等,插入失败
else
{
return false;
}
}
cur = new Node(key, value);
if (parent->_key > key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
//查找函数
Node* Find(const K& key) {
Node* cur = _root;
while (cur)
{
//查找数key比当前结点大,往右子树查找
if (cur->_key < key)
{
cur = cur->_right;
}
//查找数key比当前结点小,往左子树查找
else if (cur->_key > key)
{
cur = cur->_left;
}
//查找数key与当前结点相等,找到了
else
{
return cur;
}
}
//未找到
return nullptr;
}
//删除
bool Erase(const K& key)
{
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 = _root->_right;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_right;
}
else
{
parent->_left = cur-> _right;
}
}
}
//要删除的结点右子树为空
else if (cur->_right == nullptr)
{
//要删除的结点是根结点
if (cur == _root)
{
_root = _root->_left;
}
else
{
if (parent->_right == cur)
{
parent->_right = cur->_left;
}
else
{
parent->_left = cur->_left;
}
}
}
//要删除的结点左右子树都存在
else
{
//寻找替代结点
Node* parent = cur;
Node* rightMin = cur->_right;
while (rightMin->_left)
{
parent = rightMin;
rightMin = rightMin->_left;
}
//交换替代结点与要删除的结点的值
swap(cur->_key, rightMin->_key);
swap(cur->_val, rightMin->_val);
if (parent->_left == rightMin)
{
parent->_left = rightMin->_left;
}
else
{
parent->_right = rightMin->_left;
}
cur = rightMin;
}
delete cur;
return true;
}
}
}
//调用中序遍历函数
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;
};
//测试函数
void TestBSTree()
{
BSTree dict;
dict.Insert("insert", "插入");
dict.Insert("erase", "删除");
dict.Insert("left", "左边");
dict.Insert("string", "字符串");
string str;
while (cin >> str)
{
auto ret = dict.Find(str);
if (ret)
{
cout << str << ":" << ret->_value<< endl;
}
else
{
cout << "单词拼写错误" << endl;
}
}
string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };
// 统计水果出现的次
BSTree countTree;
for (auto str : strs)
{
auto ret = countTree.Find(str);
if (ret == NULL)
{
countTree.Insert(str, 1);
}
else
{
ret->_value++;
}
}
countTree.InOrder();
}
int main()
{
TestBSTree();
return 0;
}