文章目录
🧨前言
1、二叉搜索树的基本概念?
2、二叉搜索树的节点结构组成?
template<class K>
class BSTNode
{
public:
//构造函数,初始化列表给变量赋值
BSTNode(const K& key)
:_key(key)
,_left(nullptr)
,_right(nullptr)
{}
public:
K _key;
BSTNode<K>* _left;
BSTNode<K>* _right;
};
3、二叉搜索树的插入操作?
//插入数据函数。
bool Insert(const K& key)
{
//首先,为空的时候,直接插入到根节点。
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
//根节点不为空的时候,那就先从根节点开始。
Node* cur = _root;
Node* parent = nullptr;
//直到为空就插入
while (cur)
{
//若插入的数据值 小于 当前节点的数据值,往左走。
if (key < cur->_key)
{
//临时记录当前节点的父节点,不然后面链接不上新节点。
parent = cur;
cur = cur->_left;
}
//插入的数据值 大于 当前节点的数据值,往右走。
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else
{
//走到此处说明找到一个空位置,跳出循环进行链接。
return false;
}
}
//找到cur==nullptr,此时parent节点就是最后一个节点,在插入key时候,
//还需要判断一次,看插入的值比父节点值大,那么就当作右孩子,反之就当作左孩子。
//由于此时cur是为空的,没必要另开空间来存储新节点,因此就把key放入该节点中
cur = new Node(key);
if (key < parent->_key)
{
//插入到左边
parent->_left = cur;
}
else
{
//插入到右边
parent->_right = cur;
}
return true;
}
4、二叉搜索树的删除操作?
//查找函数
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 cur;//在判断是否存在某个值的时候,直接返回true即可。
}
}
return false;//说明没找到。
}
//删除函数
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
//先查找到对应删除的节点
while (cur)
{
if (cur->_key < key)//若当前节点的数据小于要比较的数据元素,则向右走
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
//找到节点直接后就可以删除该节点
//主要分为四种情况
//1、左右都为空;2、左位空,右不为空;3、右位空,左不为空;4、左右都不为空
// 左右为空的都可以划分到其中一个为空的情况,因为当左右都为空的时候,
//下面检测到左节点为空,则就会进入左为空的程序
//左为空
if (cur->_left == nullptr)
{
//先判断是否为根节点
if (cur == _root)
{
//直接把节点给到根节点
_root = cur->_right;
}
else if (cur == parent->_left)//若是父节点的左孩子为空,则
//把cur->_right给到父节点的左孩子
{
parent->_left = cur->_right;
}
else//反之就是把父节点的右孩子
{
parent->_right = cur->_right;
}
delete cur;
}
//右为空
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
//左右都不为空
else
{
//替代法
Node* replaceParent = cur;
//在删除左右都不为空的时候,需要找一个节点的值来替代,可以
//是当前节点的右子树的最左节点,也可以是当前节点左子树的最右节点,
//下面是用的右子树的最左节点。
Node* replace = cur->_right;
while (replace->_left)
{
replaceParent = replace;
replace = replace->_left;
}
//此处replace就是右子树的最左孩子节点
//把值给到要删除的节点,即替换
cur->_key = replace->_key;
//此时需要判断replace节点是replaceParent节点的左孩子还是右孩子
if (replace == replaceParent->_left)
{
replaceParent->_left = replace->_right;
}
else
{
replaceParent->_right = replace->_right;
}
delete replace;//相当于替换后,就删除替换的那个节点
}
return true;
}
}
//没找到就返回false
return false;
}
5、二叉搜索树的遍历?
下面把三种遍历方式都写出来:
//中序遍历搜索二叉树
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
//左 根 右
_InOrder(root->_left);
cout << root->_key<<" ";
_InOrder(root->_right);
}
void _PrevOrder(Node* root)
{
if (root == nullptr)
{
return;
}
cout << root->_key << " ";
_InOrder(root->_left);
_InOrder(root->_right);
}
void _PostOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
_InOrder(root->_right);
cout << root->_key << " ";
}
运行结果如下:
6、二叉搜索树的性能分析?
为避免性能下降,通常使用平衡二叉搜索树,如AVL树或红黑树,以保证树的高度始终接近O(log n)。后续文章会讲述。
🎉完整代码如下:
#pragma once
#include<iostream>
using namespace std;
namespace N
{
//先创建二叉树结构
template<class K>
class BSTNode
{
public:
//构造函数
BSTNode(const K& key)
:_key(key)
,_left(nullptr)
,_right(nullptr)
{}
public:
K _key;
BSTNode<K>* _left;
BSTNode<K>* _right;
};
template<class K>
class BSTree
{
typedef BSTNode<K> Node;
public:
//插入数据函数
bool Insert(const K& key)
{
//首先,为空的时候,直接插入到根节点
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
//根节点不为空的时候,那就先从根节点开始
Node* cur = _root;
Node* parent = nullptr;
//直到为空就插入
while (cur)
{
//若插入的数据小于节点的数据值,往左走
if (key < cur->_key)
{
//记录下一节点的父节点
parent = cur;
cur = cur->_left;
}
//大于节点的值
else if (key > cur->_key)
{
parent = cur;
//往右边走
cur = cur->_right;
}
//相等就返回
else
{
return false;
}
}
//找到cur==nullptr,此时parent节点就是最后一个节点,在插入key时候,
//还需要判断一次,比父节点值大,就插入到右孩子处,反之就左孩子
//由于cur是为空的,因此把key放入该节点中
cur = new Node(key);
if (key < parent->_key)
{
//插入到左边
parent->_left = cur;
}
else
{
//插入到右边
parent->_right = cur;
}
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 = nullptr;
Node* cur = _root;
//先查找到对应删除的节点
while (cur)
{
if (cur->_key < key)//若当前节点的数据小于要比较的数据元素,则向右走
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
//找到节点直接后就可以删除该节点
//主要分为四种情况
//1、左右都为空;2、左位空,右不为空;3、右位空,左不为空;4、左右都不为空
// 左右为空的都可以划分到其中一个为空的情况,因为当左右都为空的时候,
//下面检测到左节点为空,则就会进入左为空的程序
//左为空
if (cur->_left == nullptr)
{
//先判断是否为根节点
if (cur == _root)
{
//直接把节点给到根节点
_root = cur->_right;
}
else if (cur == parent->_left)//若是父节点的左孩子为空,
//则把cur->_right给到父节点的左孩子
{
parent->_left = cur->_right;
}
else//反之就是把父节点的右孩子
{
parent->_right = cur->_right;
}
delete cur;
}
//右为空
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root = cur->_left;
}
else if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
delete cur;
}
//左右都不为空
else
{
//替代法
Node* replaceParent = cur;
//在删除左右都不为空的时候,需要找一个节点的值来替代,
//可以是当前节点的右子树的最左节点
Node* replace = cur->_right;
while (replace->_left)
{
replaceParent = replace;
replace = replace->_left;
}
//此处replace就是右子树的最左孩子节点
//把值给到要删除的节点,即替换
cur->_key = replace->_key;
//此时需要判断replace节点是replaceParent节点的左孩子还是右孩子
if (replace == replaceParent->_left)
{
replaceParent->_left = replace->_right;
}
else
{
replaceParent->_right = replace->_right;
}
delete replace;//相当于替换后,就删除替换的那个节点
}
return true;
}
}
//没找到就返回false
return false;
}
void InOrder()
{
_InOrder(_root);
}
void PrevOrder()
{
_PrevOrder(_root);
}
void PostOrder()
{
_PostOrder(_root);
}
private:
//中序遍历搜索二叉树
void _InOrder(Node* root)
{
if (root == nullptr)
{
return;
}
//左 根 右
_InOrder(root->_left);
cout << root->_key<<" ";
_InOrder(root->_right);
}
void _PrevOrder(Node* root)
{
if (root == nullptr)
{
return;
}
cout << root->_key << " ";
_InOrder(root->_left);
_InOrder(root->_right);
}
void _PostOrder(Node* root)
{
if (root == nullptr)
{
return;
}
_InOrder(root->_left);
_InOrder(root->_right);
cout << root->_key << " ";
}
private:
//BSTNode<K>* _root=nullptr;//定义根节点
Node* _root = nullptr;
};
}