二叉搜索树又称二叉排序树,它可能是一棵空树,也可能是一颗具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
它的左右子树也分别为二叉搜索树。
template <class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _val;
BSTreeNode(const K& val)
:_left(nullptr)
, _right(nullptr)
, _val(val)
{}
};
从跟节点开始查找目标节点,如果目标值比根节点的值小就到根的左子树中查找,如果目标值比根节点的值大就到根节点的右子树中查找,如果找到了就返回,如果找到叶子节点都没有找到目标节点,那么该目标节点并不存在这颗二叉搜索树中。
代码实现(非递归):
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key < cur->_val)
{
cur = cur->_left;
}
else if (key > cur->_val)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
(递归):
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (root->_val < key)
{
return _FindR(root->_right, key);
}
else if (root->_val > key)
{
return _FindR(root->_left, key);
}
else
{
return true;
}
}
要想插入某个节点需要先找到该节点要插入的位置,所以跟查找的逻辑非常的像。
如果root本身是空树,就new一个key的节点给root即可。
key_val,就往左树走,key>root->_val,就往右树走,如果遇到相等的节点就应该返回了,不能插入(二叉搜索树的性质),一直走直到走到一个空树,那么这个位置就是新结点插入的位置,但是在插入之前要先用key值与该空节点的父节点的值比较一下,如果key>parent->_val,就插入到parent->right;
如果key_val。就插入到parent->left。
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_val)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
Node* newNode = new Node(key);
if (key < parent->_val)
{
parent->_left = newNode;
}
else
{
parent->_right = newNode;
}
return true;
}
(递归):
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
//注意这里用的是Node*&,代表的是上一层递归的左子树指针或者右子
//树指针的别名,直接赋值就相当于赋值给上一层递归的左子树指针
//或者右子树指针,自然就连接上了,所以无需从父节点的left或
//者right进行修改
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_val < key)
{
return _InsertR(root->_right, key);
}
else if (root->_val > key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
代码实现(非递归):
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_val)
{
parent = cur;
cur = cur->_left;
}
else
{
//1、左树为空
if (cur->_left == nullptr)
{
//删除根节点
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else if (parent->_right == cur)
{
parent->_right = cur->_right;
}
}
}
//2、右树为空
else if (cur->_right == nullptr)
{
//删除根节点
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else if (parent->_right == cur)
{
parent->_right = cur->_left;
}
}
}
//左右树都不为空
else
{
//如图有特殊情况,parent不能初始化为nullptr
Node* parent = cur;
//找左树的最大节点
Node* leftMax = cur->_left;
while (leftMax->_right)
{
parent = leftMax;
leftMax = leftMax->_right;
}
swap(leftMax->_val, cur->_val);
if (parent->_left == leftMax)
{
parent->_left = leftMax->_left;
}
else if (parent->_right = leftMax)
{
parent->_right = leftMax->_left;
}
//交换后需要更新cur
cur = leftMax;
}
delete cur;
cur = nullptr;
return true;
}
}
return false;
}
递归:
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
```cpp
//这里也是Node*&,原因同上面插入的非递归
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (root->_val < key)
{
return _EraseR(root->_right, key);
}
else if (root->_val > key)
{
return _EraseR(root->_left, key);
}
else
{
//1、左子树为空
//2、右子树为空
//3、左右子树都不为空
if (root->_left == nullptr)
{
Node* del = root;
//root是上一层的引用,修改root等于修改上一层的指
//针,等于修改parent的指针,符合题意
root = root->_right;
delete del;
del = nullptr;
}
else if (root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
del = nullptr;
}
else
{
Node* leftMax = root->_left;
while (leftMax->_right)
{
leftMax = leftMax->_right;
}
swap(leftMax->_val, root->_val);
_EraseR(root->_left, key);
}
return true;
}
}
拷贝构造就是把被拷贝的树利用前序遍历来新建一颗树即可。
先创建根节点,再递归创建左子树,最后递归创建右子树。
//拷贝构造
BSTree(const BSTree<K>& t)
{
_root = Copy(t._root);
}
Node* Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
//构建根
Node* newTree = new Node(root->_val);
//构建左子树
newTree->_left = Copy(root->_left);
//构建右子树
newTree->_right = Copy(root->_right);
//返回这棵树
return newTree;
}
//赋值
//依然是利用现代写法,利用传参的拷贝构造得到一颗
//局部临时的树,再交换root指针即可
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
析构函数就是利用后序遍历的思想把整棵树的每一个节点释放掉,即先析构左子树,再析构右子树,最后析构根节点。
//析构
~BSTree()
{
_Destroy(_root);
}
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
if (root->_left)
{
_Destroy(root->_left);
}
if (root->_right)
{
_Destroy(root->_right);
}
delete root;
root = nullptr;
}
namespace key
{
template <class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _val;
BSTreeNode(const K& val)
:_left(nullptr)
, _right(nullptr)
, _val(val)
{}
};
template <class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
BSTree()
:_root(nullptr)
{}
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key < cur->_val)
{
cur = cur->_left;
}
else if (key > cur->_val)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_val)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
Node* newNode = new Node(key);
if (key < parent->_val)
{
parent->_left = newNode;
}
else
{
parent->_right = newNode;
}
return true;
}
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_val)
{
parent = cur;
cur = cur->_left;
}
else
{
//1、左树为空
if (cur->_left == nullptr)
{
//删除根节点
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else if (parent->_right == cur)
{
parent->_right = cur->_right;
}
}
}
//2、右树为空
else if (cur->_right == nullptr)
{
//删除根节点
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else if (parent->_right == cur)
{
parent->_right = cur->_left;
}
}
}
//左右树都不为空
else
{
//如图有特殊情况,parent不能初始化为nullptr
Node* parent = cur;
//找左树的最大节点
Node* leftMax = cur->_left;
while (leftMax->_right)
{
parent = leftMax;
leftMax = leftMax->_right;
}
swap(leftMax->_val, cur->_val);
if (parent->_left == leftMax)
{
parent->_left = leftMax->_left;
}
else if (parent->_right = leftMax)
{
parent->_right = leftMax->_left;
}
//交换后需要更新cur
cur = leftMax;
}
delete cur;
cur = nullptr;
return true;
}
}
return false;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
//析构
~BSTree()
{
_Destroy(_root);
}
//拷贝构造
BSTree(const BSTree<K>& t)
{
_root = Copy(t._root);
}
//赋值
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
private:
Node* Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
Node* newTree = new Node(root->_val);
newTree->_left = Copy(root->_left);
newTree->_right = Copy(root->_right);
return newTree;
}
void _Destroy(Node* root)
{
if (root == nullptr)
{
return;
}
if (root->_left)
{
_Destroy(root->_left);
}
if (root->_right)
{
_Destroy(root->_right);
}
delete root;
root = nullptr;
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (root->_val < key)
{
return _FindR(root->_right, key);
}
else if (root->_val > key)
{
return _FindR(root->_left, key);
}
else
{
return true;
}
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_val < key)
{
return _InsertR(root->_right, key);
}
else if (root->_val > key)
{
return _InsertR(root->_left, key);
}
else
{
return false;
}
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (root->_val < key)
{
return _EraseR(root->_right, key);
}
else if (root->_val > key)
{
return _EraseR(root->_left, key);
}
else
{
//1、左子树为空
//2、右子树为空
//3、左右子树都不为空
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
del = nullptr;
}
else if (root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
del = nullptr;
}
else
{
Node* leftMax = root->_left;
while (leftMax->_right)
{
leftMax = leftMax->_right;
}
swap(leftMax->_val, root->_val);
_EraseR(root->_left, key);
}
return true;
}
}
void _InOrder(Node* _root)
{
if (_root == nullptr)
{
return;
}
_InOrder(_root->_left);
cout << _root->_val << " ";
_InOrder(_root->_right);
}
private:
Node* _root;
};
void TestBSTree1()
{
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
BSTree<int> t;
for (auto e : a)
{
t.Insert(e);
}
t.InOrder();
t.Erase(4);
t.InOrder();
t.Erase(6);
t.InOrder();
t.Erase(7);
t.InOrder();
t.Erase(3);
t.InOrder();
for (auto e : a)
{
t.Erase(e);
t.InOrder();
}
}
void TestBSTree2()
{
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
BSTree<int> t1;
for (auto e : a)
{
t1.InsertR(e);
}
BSTree<int> t;
t = t1;
t.InOrder();
t.EraseR(4);
t.InOrder();
t.EraseR(6);
t.InOrder();
t.Erase(7);
t.InOrder();
t.EraseR(3);
t.InOrder();
for (auto e : a)
{
t.EraseR(e);
t.InOrder();
}
}
}
其实Key–Value模型的二叉搜索树和Key模型的二叉搜索树基本上是一样的,只不过在树的节点中多存放一个value值,所以代码实现如下。
namespace key_value
{
template <class K,class V>
struct BSTreeNode
{
BSTreeNode<K,V>* _left;
BSTreeNode<K,V>* _right;
K _key;
V _value;
BSTreeNode(const K& key,const V& value)
:_left(nullptr)
, _right(nullptr)
, _key(key)
,_value(value)
{}
};
template <class K,class V>
class BSTree
{
typedef BSTreeNode<K,V> Node;
public:
BSTree()
:_root(nullptr)
{}
Node* Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (key < cur->_key)
{
cur = cur->_left;
}
else if (key > cur->_key)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return 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)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
Node* newNode = new Node(key, value);
if (key < parent->_key)
{
parent->_left = newNode;
}
else
{
parent->_right = newNode;
}
return true;
}
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else
{
//找到了
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else if (parent->_right == cur)
{
parent->_right = cur->_right;
}
}
}
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else if (parent->_right == cur)
{
parent->_right = cur->_left;
}
}
}
else
{
Node* parent = cur;
Node* leftMax = cur->_left;
while (leftMax->_right)
{
parent = leftMax;
leftMax = leftMax->_right;
}
swap(leftMax->_key, cur->_key);
swap(leftMax->_value, cur->_value);
if (parent->_left == leftMax)
{
parent->_left = leftMax->_left;
}
else if (parent->_right = leftMax)
{
parent->_right = leftMax->_left;
}
cur = leftMax;
}
delete cur;
cur = nullptr;
return true;
}
}
return false;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
Node* FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key,const V& value)
{
return _InsertR(_root, key, value);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
private:
Node* _FindR(Node* root, const K& key)
{
if (root == nullptr)
{
return nullptr;
}
if (root->_key < key)
{
return _FindR(root->_right, key);
}
else if (root->_key > key)
{
return _FindR(root->_left, key);
}
else
{
return root;
}
}
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->_right, key, value);
}
else if (root->_key > key)
{
return _InsertR(root->_left, key, value);
}
else
{
return false;
}
}
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
{
return false;
}
if (root->_key < key)
{
return _EraseR(root->_right, key);
}
else if (root->_key > key)
{
return _EraseR(root->_left, key);
}
else
{
//1、左子树为空
//2、右子树为空
//3、左右子树都不为空
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
del = nullptr;
}
else if (root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
del = nullptr;
}
else
{
Node* leftMax = root->_left;
while (leftMax->_right)
{
leftMax = leftMax->_right;
}
swap(leftMax->_val, root->_val);
swap(leftMax->_value, root->_value);
_EraseR(root->_left, key);
}
return true;
}
}
void _InOrder(Node* _root)
{
if (_root == nullptr)
{
return;
}
_InOrder(_root->_left);
cout << _root->_key << ":" << _root->_value << endl;
_InOrder(_root->_right);
}
private:
Node* _root;
};
void TestBSTree1()
{
string arr[] = { "苹果","苹果","香蕉","雪梨","草莓" };
BSTree<string,int> t;
for (const auto e : arr)
{
auto ret = t.FindR(e);
if (ret == nullptr)
{
t.InsertR(e, 1);
}
else
{
ret->_value++;
}
}
t.InOrder();
}
void TestBSTree2()
{
BSTree<string, string> dict;
dict.InsertR("sort", "排序");
dict.InsertR("left", "左边");
dict.InsertR("right", "右边");
string str;
while (cin >> str)
{
auto ret = dict.FindR(str);
if (ret)
{
cout << ret->_key << ":" << ret->_value << endl;
}
else
{
cout << "无此单词" << endl;
}
}
}
}
key模型:判断数据在不在,例如学校门禁系统,扫脸确认该学生在不在学校的教务信息管理系统中。
key-value:判断在不在,在的同时把与之相关的绑定的信息返回,例如英译中的字典,统计每种书本的数目等。
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:logN
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:N
所以二叉搜索树的性能并不能得到很好的保证,我们该如何改进这棵树,使它避免在极端情况下退化成链表呢?
就是在接下来的AVL树和红黑树中实现。
好啦,以上就是今天想要跟大家分享的全部内容啦,你学会了嘛?如果感觉有所收获,你就点一下小心心,点点关注呗,后期还会持续更新C++相关的知识哦,我们下期见!!!!!