【C++进阶】二叉搜索树
🥕个人主页:开敲🍉
🔥所属专栏:C++🥭
🌼文章目录🌼
1. 二叉搜索树的概念
二叉搜索树又称二叉排序树,它或者是一颗空树,或者是具有以下性质的二叉树:
① 若它的左子树不为空,则左子树上节点的值都小于等于根节点的值。
② 若它的右子树不为空,则右子树上节点的值都大于等于根节点的值。
③ 它的左右子树也要满足 二叉搜索树 的性质。
④ 二叉搜索树中可以支持插入相等的值,也可以不支持插入相等的值,具体看使用的场景。
2. 二叉搜索树的性能分析
最优情况下,二叉搜索树为完全二叉树,其高度为:log(N),时间复杂度为:O(log(N))。
最坏情况下,二叉搜索树为单链表形态,其高度为:(N/2),时间复杂度为:O(N)。
所以综合而言,二叉搜索树的时间复杂度为:O(N)。
3. 二叉搜索树的插入
插入的具体过程如下:
① 树为空,则直接插入节点,并且使其作为根节点。
② 树不为空,根据二叉搜索树的性质:插入值比当前节点大往右走;插入值比当前节点小往左走;如果我们实现的是允许插入相同值的二叉搜索树,则插入值与当前节点值相同时,往左往右都可以。找到空位置后插入新节点。
不支持插入相同值的二叉搜索树的插入参考代码:
void Insert(const K& key)
{
if (!_root) _root = new Node(key);
else
{
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;
}
if (parent->_key > key) parent->left = new Node(key);
else if (parent->_key < key) parent->right = new Node(key);
}
}
支持插入相同值的二叉搜索树的插入参考代码:
void Insert(const K& key)
{
if (!_root) _root = new Node(key);
else
{
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;
}
if (parent->_key >= key) parent->left = new Node(key);
else if (parent->_key < key) parent->right = new Node(key);
}
}
4. 二叉搜索树的查找
① 从根开始比较,查找x。x比当前节点的值大就往右查找;x比当前节点的值小就往左查找。
② 查找高度次,如果走到空了则说明这个值不存在。
③ 如果不支持插入相同的值,查找到x就可以返回;如果支持,则需要查找到中序遍历的第一个x。
不支持插入相同值的二叉搜索树的查找参考代码:
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;
}
5. 二叉搜索树的删除
从根开始查找元素。如果查找到空,则说明要删除的值不存在;否则,要删除的元素存在,分为以下四种情况处理:(假设要删除节点为 N)
① 要删除的节点为叶子节点:此时直接将 N 删除,使其父节点指向 N 的指针指向nullptr。
② 要删除的节点左孩子为空,而右孩子不为空:此时我们将其父节点指向 N 位置的指针指向 N->right。通俗一点的理解就是将我的孩子托付给父亲,随后删除我。
③ 要删除的节点左孩子不为空,右孩子为空:此时我们将其父节点指向 N 位置的指针指向 N->left。
④ 要删除的节点左右孩子均不为空:这种情况最为复杂。我们此时无法直接删除 N ,因为 N 左右均有孩子无处安放,此时有一个方法专门解决这个问题;我们去 N 节点的左子树寻找最大值(max) 或者 去 N 节点的右子树寻找最小值(min)。让这个值和 N 的值进行交换,随后删除 max 或 min 原本所在节点。
二叉搜索树的删除参考代码:
void Delete(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 (IsLeafNode(cur))//情况 ①
{
if (!parent) _root = nullptr;
else
{
if (parent->left == cur) parent->left = nullptr;
if (parent->right == cur) parent->right = nullptr;
}
}
else
{
if (!cur->right)//情况 ③
{
if (cur == _root) _root = cur->left;
else
{
if (parent->left == cur) parent->left = cur->left;
else parent->right = cur->left;
}
}
else if (!cur->left)//情况 ②
{
if (cur == _root) _root = cur->right;
else
{
if (parent->left == cur) parent->left = cur->right;
else parent->right = cur->right;
}
}
else//情况 ④
{
parent = cur;
Node* tmp = cur->right;
while (tmp->left)
{
parent = tmp;
tmp = tmp->left;
}
swap(cur->_key, tmp->_key);
if (parent->left == tmp) parent->left = tmp->right;
else parent->right = tmp->right;
}
}
break;
}
}
}
6. 二叉搜索树的实现代码
//不允许插入相同值
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <class K>
class BSTreeNodeK
{
public:
K _key;
BSTreeNodeK* left;
BSTreeNodeK* right;
BSTreeNodeK(const K& key)
:_key(key),
left(nullptr),
right(nullptr)
{}
};
template <class K>
class BSTreeK
{
typedef BSTreeNodeK<K> Node;
public:
void Insert(const K& key)
{
if (!_root) _root = new Node(key);
else
{
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;
}
if (parent->_key > key) parent->left = new Node(key);
else if (parent->_key < key) parent->right = new Node(key);
}
}bool IsLeafNode(Node* root) { return !root->left && !root->right; }
void Delete(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 (IsLeafNode(cur))
{
if (!parent) _root = nullptr;
else
{
if (parent->left == cur) parent->left = nullptr;
if (parent->right == cur) parent->right = nullptr;
}
}
else
{
if (!cur->right)
{
if (cur == _root) _root = cur->left;
else
{
if (parent->left == cur) parent->left = cur->left;
else parent->right = cur->left;
}
}
else if (!cur->left)
{
if (cur == _root) _root = cur->right;
else
{
if (parent->left == cur) parent->left = cur->right;
else parent->right = cur->right;
}
}
else
{
parent = cur;
Node* tmp = cur->right;
while (tmp->left)
{
parent = tmp;
tmp = tmp->left;
}
swap(cur->_key, tmp->_key);
if (parent->left == tmp) parent->left = tmp->right;
else parent->right = tmp->right;
}
}
break;
}
}
}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;
}void Precedent()
{
Node* pmove = _root;
_Precedent(pmove);
cout << endl;
}
private:void _Precedent(Node* root)
{
if (!root) return;
_Precedent(root->left);
cout << root->_key << ' ';
_Precedent(root->right);
}
Node* _root = nullptr;
};// key_value 二叉搜索树
//使用场景:停车场计费系统、中译英系统等
template <class K,class V>
class BSTreeNodeKV
{
public:
K _key;
V _value;
BSTreeNodeKV* left;
BSTreeNodeKV* right;
BSTreeNodeKV(const K& key,const V& value)
:_key(key),
_value(value),
left(nullptr),
right(nullptr)
{}
};
template <class K,class V>
class BSTreeKV
{
typedef BSTreeNodeKV<K,V> Node;
public:
void Insert(const K& key,const V& value)
{
if (!_root) _root = new Node(key,value);
else
{
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;
}
if (parent->_key > key) parent->left = new Node(key,value);
else if (parent->_key < key) parent->right = new Node(key,value);
}
}bool IsLeafNode(Node* root) { return !root->left && !root->right; }
void Delete(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 (IsLeafNode(cur))
{
if (!parent) _root = nullptr;
else
{
if (parent->left == cur) parent->left = nullptr;
if (parent->right == cur) parent->right = nullptr;
}
}
else
{
if (!cur->right)
{
if (cur == _root) _root = cur->left;
else
{
if (parent->left == cur) parent->left = cur->left;
else parent->right = cur->left;
}
}
else if (!cur->left)
{
if (cur == _root) _root = cur->right;
else
{
if (parent->left == cur) parent->left = cur->right;
else parent->right = cur->right;
}
}
else
{
parent = cur;
Node* tmp = cur->right;
while (tmp->left)
{
parent = tmp;
tmp = tmp->left;
}
swap(cur->_key, tmp->_key);
if (parent->left == tmp) parent->left = tmp->right;
else parent->right = tmp->right;
}
}
break;
}
}
}string 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->_value;
}
return "false";
}void Precedent()
{
Node* pmove = _root;
_Precedent(pmove);
cout << endl;
}
private:void _Precedent(Node* root)
{
if (!root) return;
_Precedent(root->left);
cout << root->_key << ' ';
_Precedent(root->right);
}
Node* _root = nullptr;
};
创作不易,点个赞呗,蟹蟹啦~