文章目录
- 1. 搜索二叉树的概念
- 2. 搜索二叉树结构的定义
- 3. 搜索二叉树的操作
- 3.1 搜索二叉树的插入
- 3.2 搜索二叉树的删除
- 3.3 搜索二叉树的查找
- 4. 完整代码
1. 搜索二叉树的概念
二叉搜索树(Binary Search Tree,简称 BST),又称二叉排序树,是一种特殊的二叉树。
二叉搜索树可以是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
- 递归性质:它的左右子树也分别为二叉搜索树。
2. 搜索二叉树结构的定义
搜索二叉树可以存储任何类型的数据,因此这里使用模板来实现搜索二叉树(模板允许我们创建一个泛型的节点结构,可以存储任意类型的值)。
一个二叉搜索树(BST)是一个节点的集合,这些节点具有如下结构:
- 一个存储的值(_val)。
- 指向左子节点的指针(_left,可以为空)。
- 指向右子节点的指针(_right,可以为空)。
节点具体定义如下:
template<class K>
struct TreeNode
{
TreeNode<K>* _left;
TreeNode<K>* _right;
K _val;
//构造函数
TreeNode(const K& val)
:_left(nullptr)
,_right(nullptr)
,_val(val)
{}
};
搜索二叉树结构的定义:
template<class K>
class BSTree
{
public:
typedef TreeNode<K> Node;
private:
Node* _root = nullptr;//根节点指针 _root为空代表空树
};
3. 搜索二叉树的操作
3.1 搜索二叉树的插入
插入操作的具体过程
- 树为空:如果树为空,直接创建一个新节点,并将其赋值给根指针。
- 树不空:从根节点开始,比较待插入值与当前节点的值。
如果待插入值小于当前节点的值,递归或迭代地在当前节点的左子树中查找插入位置。
如果待插入值大于当前节点的值,递归或迭代地在当前节点的右子树中查找插入位置。
在找到适当的空位置后,插入新节点。
非递归操作过程如下:
非递归代码如下:
bool Insert(const K& val)
{
// 树为空,直接创建一个新节点,并将其赋值给根指针
if (_root == nullptr)
{
_root = new Node(val);
return true;
}
//树不空,从根节点开始,比较待插入值与当前节点的值,直到cur走到空
//找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_val > val)
{
cur = cur->_left;
}
else if (cur->_val < val)
{
cur = cur->_right;
}
else
{
return false;
}
}
//插入
cur = new Node(val);
if (val > parent->_val)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
递归操作过程如下:
递归代码如下:
bool _InsertR(Node*& root, const K& val)
{
//1.树为空时,直接创建一个新节点,并将其赋值给root,这里的root是_root的引用
//2.树为不空时,root其父节点的_right或者_left的引用
if (root == nullptr)
{
root = new Node(val);
return true;
}
//待插入值小于当前节点的值,递归去当前节点的左子树中查找插入位置
if (root->_val > val)
{
return _InsertR(root->_left, val);
}
else if (root->_val < val)//待插入值大于当前节点的值,递归去在当前节点的右子树中查找插入位置
{
return _InsertR(root->_right, val);
}
else
{
return false;
}
}
bool InsertR(const K& val)
{
return _InsertR(_root, val);
}
3.2 搜索二叉树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
- a. 要删除的结点无孩子结点
- b. 要删除的结点只有左孩子结点
- c. 要删除的结点只有右孩子结点
- d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程
如下:
- 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
- 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
- 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),或者在它的左子树中寻找中序下的最后一个结点(关键码最大),用它的值填补到被删除节点中,再来处理该结点的删除问题—替换法删除
画个图理解一下:
非递归代码如下:
bool Erase(const K& val)
{
Node* parent = nullptr;//记录当前节点的父节点,初始时为空
Node* cur = _root;//记录当前节点
while (cur)
{
//待删除值大于当前节点的值,去当前节点的右子树去中查找删除
if (val > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (val < cur->_val)//待删除值小于当前节点的值,去当前节点的左子树去中查找删除
{
parent = cur;
cur = cur->_left;
}
else
{
//准备删除
if (cur->_left == nullptr)//左为空
{
//父节点为空,说明删除的是根节点
if (parent == nullptr)
{
_root = cur->_right;
}
else
{
//将自己的右孩子托管给父节点
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)//右为空
{
//父节点为空,说明删除的是根节点
if (parent == nullptr)
{
_root = cur->_left;
}
else
{
//将自己的左孩子托管给父节点
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{
//找右子树最左节点
Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
parent = subLeft;
subLeft = subLeft->_left;
}
swap(subLeft->_val, cur->_val);//替换
//删除替换节点
if (parent->_left == subLeft)
{
parent->_left = subLeft->_right;
}
else
{
parent->_right = subLeft->_right;
}
delete subLeft;
}
return true;
}
}
return false;
}
递归代码如下:
bool _EraseR(Node*& root, const K& val)
{
if (root == nullptr) return false;
//待删除值小于当前节点的值,递归去当前节点的左子树去中查找删除
if (root->_val > val)
{
return _EraseR(root->_left, val);
}
else if (root->_val < val)//待删除值大于当前节点的值,递归去当前节点的右子树去中查找删除
{
return _EraseR(root->_right, val);
}
else
{
//开始删除
//左为空,将自己的右孩子托管给父节点
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
}
else if (root->_right == nullptr)//右为空,将自己的左孩子托管给父节点
{
Node* del = root;
root = root->_left;
delete del;
}
else
{
//找左子树的最右节点替换删除
Node* parent = root;
Node* subRight = root->_left;
while (subRight->_right)
{
parent = subRight;
subRight = subRight->_right;
}
swap(subRight->_val, root->_val);
_EraseR(root->_left, subRight->_val);
}
return true;
}
}
bool EraseR(const K& val)
{
return _EraseR(_root, val);
}
3.3 搜索二叉树的查找
具体操作步骤如下:
- 从根开始比较,查找,比根大去其右子树中查找,比根小则去其左子树中查找。
- 最多查找高度次,走到到空,还没找到,这个值不存在。
非递归代码如下:
bool Find(const K& val)
{
Node* cur = _root;
while (cur)
{
if (cur->_val > val)
{
cur = cur->_left;
}
else if (cur->_val < val)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
递归代码如下:
bool FindR(const K& val)
{
return _FindR(_root, val);
}
bool _FindR(Node* root, const K& val)
{
if (root == nullptr) return false;
if (root->_val > val)
{
return _FindR(root->_left, val);
}
else if (root->_val < val)
{
return _FindR(root->_right, val);
}
else
{
return true;
}
}
4. 完整代码
#include <iostream>
using namespace std;
template<class K>
struct TreeNode
{
TreeNode<K>* _left;
TreeNode<K>* _right;
K _val;
TreeNode(const K& val)
:_left(nullptr)
,_right(nullptr)
,_val(val)
{}
};
template<class K>
class BSTree
{
public:
typedef TreeNode<K> Node;
bool Insert(const K& val)
{
if (_root == nullptr)
{
_root = new Node(val);
return true;
}
//找插入位置
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_val > val)
{
cur = cur->_left;
}
else if (cur->_val < val)
{
cur = cur->_right;
}
else
{
return false;
}
}
//插入
cur = new Node(val);
if (val > parent->_val)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
//bool Erase(const K& val)
//{
// Node* parent = nullptr;
// Node* cur = _root;
// while (cur)
// {
// if (cur->_val > val)
// {
// parent = cur;
// cur = cur->_left;
// }
// else if (cur->_val < val)
// {
// parent = cur;
// cur = cur->_right;
// }
// else
// {
// //准备删除
// if (cur->_left == nullptr)
// {//左为空
// if (parent == nullptr)
// {
// _root = cur->_right;
// }
// else
// {
// if (parent->_left == cur)
// {
// parent->_left = cur->_right;
// }
// else
// {
// parent->_right = cur->_right;
// }
// }
// delete cur;
// }
// else if (cur->_right == nullptr)
// {//右为空
// if (parent == nullptr)
// {
// _root = cur->_left;
// }
// else
// {
// if (parent->_left == cur)
// {
// parent->_left = cur->_left;
// }
// else
// {
// parent->_right = cur->_left;
// }
// }
// delete cur;
// }
// else
// {
// //都不为空
// //找左树的最右节点或者右树的最左节点
// Node* parent = cur;
// Node* subRight = cur->_left;
// while (subRight->_right)
// {
// parent = subRight;
// subRight = subRight->_right;
// }
// swap(subRight->_val, cur->_val);
// if (parent->_left == subRight)
// {
// parent->_left = subRight->_left;
// }
// else
// {
// parent->_right = subRight->_left;
// }
// delete subRight;
// }
// return true;
// }
// }
// return false;
//}
bool Erase(const K& val)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (val > cur->_val)
{
parent = cur;
cur = cur->_right;
}
else if (val < cur->_val)
{
parent = cur;
cur = cur->_left;
}
else
{//准备删除
if (cur->_left == nullptr)//左为空
{
if (parent == nullptr)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)//右为空
{
if (parent == nullptr)
{
_root = cur->_left;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{
//找右子树最左节点
Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
parent = subLeft;
subLeft = subLeft->_left;
}
swap(subLeft->_val, cur->_val);
if (parent->_left == subLeft)
{
parent->_left = subLeft->_right;
}
else
{
parent->_right = subLeft->_right;
}
delete subLeft;
}
return true;
}
}
return false;
}
bool Find(const K& val)
{
Node* cur = _root;
while (cur)
{
if (cur->_val > val)
{
cur = cur->_left;
}
else if (cur->_val < val)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
bool FindR(const K& val)
{
return _FindR(_root, val);
}
bool InsertR(const K& val)
{
return _InsertR(_root, val);
}
bool EraseR(const K& val)
{
return _EraseR(_root, val);
}
//中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
private:
bool _EraseR(Node*& root, const K& val)
{
if (root == nullptr) return false;
if (root->_val > val)
{
return _EraseR(root->_left, val);
}
else if (root->_val < val)
{
return _EraseR(root->_right, val);
}
else
{
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
}
else if (root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
}
else
{
Node* parent = root;
Node* subRight = root->_left;
while (subRight->_right)
{
parent = subRight;
subRight = subRight->_right;
}
swap(subRight->_val, root->_val);
_EraseR(root->_left, subRight->_val);
}
return true;
}
}
bool _InsertR(Node*& root, const K& val)
{
if (root == nullptr)
{
root = new Node(val);
return true;
}
if (root->_val > val)
{
return _InsertR(root->_left, val);
}
else if (root->_val < val)
{
return _InsertR(root->_right, val);
}
else
{
return false;
}
}
bool _FindR(Node* root, const K& val)
{
if (root == nullptr) return false;
if (root->_val > val)
{
return _FindR(root->_left, val);
}
else if (root->_val < val)
{
return _FindR(root->_right, val);
}
else
{
return true;
}
}
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_val << ' ';
_InOrder(root->_right);
}
private:
Node* _root = nullptr;//根节点指针 _root为空代表空树
};
int main()
{
BSTree<int> bt;
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
for (auto e : a)
{
bt.InsertR(e);
}
bt.InOrder();
for (auto e : a)
{
bt.Erase(e);
bt.InOrder();
}
return 0;
}
运行结果如下:
至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !!!