二叉搜索树是AVL树和红黑树的基础, 学好二叉搜索树,有助于更好的理解map和set的特性。
概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 。
- 它的左右子树也分别为二叉搜索树。
如图即为一颗二叉搜索树:
如果按中序遍历的话应该为递增顺序: 9,17, 23, 45, 5 3, 65, 78, 81, 87, 94
定义二叉树节点:
class BSTNode
{
friend class BSTree<_Ty>;
public:
BSTNode() : data(_Ty()), leftChild(nullptr), rightChild(nullptr)
{}
BSTNode(_Ty val, BSTNode* left = nullptr, BSTNode* right = nullptr)
: data(val), leftChild(left), rightChild(right)
{}
~BSTNode()
{}
private:
_Ty data;
BSTNode* leftChild;
BSTNode* rightChild;
};
定义二叉树:
class BSTree
{
public:
BSTree():root(nullptr)
{}
BSTree(vector<_Ty> & num) : root(nullptr)
{
for (const auto e : num) {
Insert1(root, e);
//Insert2(root,e);
}
}
~BSTree()
{}
/// <summary>
/// 核心功能 增删
/// <returns>
bool Insert(const _Ty& x)
{
return Insert2(root, x);
//return Insert1(root, x);
}
bool Remove(const _Ty& key)
{
return Remove1(root, key);
//return Remove2(root, key);
}
private:
BSTNode<_Ty>* root;
};
构造二叉树时需要用逐个元素插入;而插入就要先查找到该插入的位置;
查找
BSTNode<_Ty>* Search(BSTNode<_Ty>* t, const _Ty& key)const
{
if (t == nullptr)
return t;
if (key < t->data)
return Search(t->leftChild, key);
else if (key > t->data)
return Search(t->rightChild, key);
return t;
}
插入
bool Insert1(BSTNode<_Ty>*& t, int x) //递归
{
if (t == nullptr) {
t = new BSTNode<_Ty>(x);
return true;
}
if (x > t->data) {
return Insert1(t->rightChild, x);
}
if (x < t->data) {
return Insert1(t->leftChild, x);
}
return false;
}
bool Insert2(BSTNode<_Ty>* &t, const _Ty& x) //非递归 需要找到当前节点的父节点
{
if (t == nullptr) {
t = new BSTNode<_Ty>(x);
return true;
}
BSTNode<_Ty>* p = t; //当前节点
BSTNode<_Ty>* pre = t; //父节点
while (p) { //比较大小走到分支尽头结束,此时p=nullptr
pre = p;
if (x > t->data) {
p = p->rightChild;
}
else if (x < t->data) {
p = p->leftChild;
}
}
//然后比较x和pre->data的大小决定插入的是左子树还是右子树
if (x > pre->data) {
pre->rightChild= new BSTNode<_Ty>(x);
}
else {
pre->leftChild = new BSTNode<_Ty>(x);
}
return true;
}
删除
删除操作比较复杂一点:
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
- 要删除的结点只有左孩子结点。
- 要删除的结点只有右孩子结点 。
- 要删除的结点有左、右孩子结点
- 要删除的结点无左、右孩子结点
前三种情况删除节点后需要调整:
考虑完前三种情况就剩下第四种情况,第四种情况可以包含到1,2 情况中。
bool Remove1(BSTNode<_Ty>* &t, const _Ty& key) //递归
{
if (t == nullptr)
return false;
if (key < t->data)
return Remove1(t->leftChild,key);
else if (key > t->data)
return Remove1(t->rightChild, key);
else{ //找到了则删除
if (t->leftChild && t->rightChild) { //左右子树都不空
BSTNode<_Ty> * q = t->rightChild;
while (q->leftChild)
q = q->leftChild; //找右子树最小值
t->data = q->data;
Remove1(t->rightChild, t->data); //删除刚才被置换的节点
}
else { // 三种情况:左子树空 或者右子树空 或者左右子树都为空
BSTNode<_Ty>* p = t;
if (t->leftChild != nullptr) //左树不空
t = t->leftChild;
else //右树不空
t = t->rightChild;
delete p;
}
}
return true;
}
bool Remove2(BSTNode<_Ty>*& t, const _Ty& key) //非递归
{
if (t == nullptr)
return false;
BSTNode<_Ty>* cur = Search(key);
if (cur == nullptr)
return false;
if (cur->leftChild && cur->rightChild) { //左右子树都存在 可选择替换右子树的最小值或左子树的最大值
BSTNode<_Ty>* q = cur->leftChild;
while (q->rightChild != nullptr)
q = q->rightChild;
cur->data = q->data;
cur = q;
}
BSTNode<_Ty>* p = Parent(t,cur); //获取父节点
if (p == nullptr) //删除根节点 此时只有左树或者右树 或者都无
{
if (cur->leftChild != nullptr)
cur = cur->leftChild;
else
cur = cur->rightChild;
}
else { //非根节点
if (p->leftChild==cur) { //cur为左树 且cur只有一颗子树
if (cur->leftChild == nullptr)
p->leftChild = cur->rightChild;
else
p->leftChild = cur->leftChild;
}
else if (p->rightChild== cur) {//cur为右树 且cur只有一颗子树
if (cur->leftChild == nullptr)
p->rightChild = cur->rightChild;
else
p->rightChild = cur->leftChild;
}
}
delete cur;
return true;
}
二叉搜索树的性能
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log 2 N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2 。 优化方案----->可使用平衡二叉搜索树
完整代码
#include <iostream>
#include <vector>
using namespace std;
template<class _Ty>
class BSTree;
template<class _Ty>
class BSTNode
{
friend class BSTree<_Ty>;
public:
BSTNode() : data(_Ty()), leftChild(nullptr), rightChild(nullptr)
{}
BSTNode(_Ty val, BSTNode* left = nullptr, BSTNode* right = nullptr)
: data(val), leftChild(left), rightChild(right)
{}
~BSTNode()
{}
private:
_Ty data;
BSTNode* leftChild;
BSTNode* rightChild;
};
template<class _Ty>
class BSTree
{
public:
BSTree():root(nullptr)
{}
BSTree(vector<_Ty> & num) : root(nullptr)
{
for (const auto e : num) {
Insert1(root, e);
//Insert2(root,e);
}
}
~BSTree()
{}
/// 核心功能 增删
bool Insert(const _Ty& x)
{
return Insert2(root, x);
//return Insert1(root, x);
}
bool Remove(const _Ty& key)
{
return Remove1(root, key);
//return Remove2(root, key);
}
/// 其它功能
public:
void Order()const //中序遍历 方便查看结果
{
Order(root);
}
BSTNode<_Ty>* Min()const //求树最小值
{
return Min(root);
}
BSTNode<_Ty>* Max()const //求树最大值
{
return Max(root);
}
BSTNode<_Ty>* Parent(BSTNode<_Ty>* key)const //寻找节点的父节点
{
return Parent(root, key);
}
BSTNode<_Ty>* Search(const _Ty& key)const
{
return Search(root, key);
}
protected:
bool Insert1(BSTNode<_Ty>*& t, int x) //递归
{
if (t == nullptr) {
t = new BSTNode<_Ty>(x);
return true;
}
if (x > t->data) {
return Insert1(t->rightChild, x);
}
if (x < t->data) {
return Insert1(t->leftChild, x);
}
return false;
}
bool Insert2(BSTNode<_Ty>* &t, const _Ty& x) //非递归 需要找到当前节点的父节点
{
if (t == nullptr) {
t = new BSTNode<_Ty>(x);
return true;
}
BSTNode<_Ty>* p = t; //当前节点
BSTNode<_Ty>* pre = t; //父节点
while (p) { //比较大小走到分支尽头结束,此时p=nullptr
pre = p;
if (x > t->data) {
p = p->rightChild;
}
else if (x < t->data) {
p = p->leftChild;
}
}
//然后比较x和pre->data的大小决定插入的是左子树还是右子树
if (x > pre->data) {
pre->rightChild= new BSTNode<_Ty>(x);
}
else {
pre->leftChild = new BSTNode<_Ty>(x);
}
return true;
}
bool Remove1(BSTNode<_Ty>* &t, const _Ty& key) //递归
{
if (t == nullptr)
return false;
if (key < t->data)
return Remove1(t->leftChild,key);
else if (key < t->data)
return Remove1(t->rightChild, key);
else{ //找到了则删除
if (t->leftChild && t->rightChild) {
BSTNode<_Ty> * q = t->rightChild;
while (q->leftChild)
q = q->leftChild;
t->data = q->data;
Remove1(t->rightChild, t->data);
}
else {
BSTNode<_Ty>* p = t;
if (t->leftChild != nullptr)
t = t->leftChild;
else
t = t->rightChild;
delete p;
}
}
return true;
}
bool Remove2(BSTNode<_Ty>*& t, const _Ty& key)
{
if (t == nullptr)
return false;
BSTNode<_Ty>* cur = Search(key);
if (cur == nullptr)
return false;
if (cur->leftChild && cur->rightChild) { //左右子树都存在 可选择替换右子树的最小值或左子树的最大值
BSTNode<_Ty>* q = cur->leftChild;
while (q->rightChild != nullptr)
q = q->rightChild;
cur->data = q->data;
cur = q;
}
BSTNode<_Ty>* p = Parent(t,cur);
if (p == nullptr) //删除根节点 此时只有左树或者右树 或者都无
{
if (cur->leftChild != nullptr)
cur = cur->leftChild;
else
cur = cur->rightChild;
}
else { //非根节点
if (p->leftChild==cur) { //cur为左树 且cur只有一颗子树
if (cur->leftChild == nullptr)
p->leftChild = cur->rightChild;
else
p->leftChild = cur->leftChild;
}
else if (p->rightChild== cur) {//cur为右树 且cur只有一颗子树
if (cur->leftChild == nullptr)
p->rightChild = cur->rightChild;
else
p->rightChild = cur->leftChild;
}
}
delete cur;
return true;
}
protected:
void Order(BSTNode<_Ty>* t)const //中序遍历 方便查看结果
{
if (t == nullptr) {
return;
}
Order(t->leftChild);
printf("%d ", t->data);
Order(t->rightChild);
}
BSTNode<_Ty>* Min(BSTNode<_Ty>*&t)
{
while (t&&t->leftChild != nullptr) { //t==nullptr时返回nullptr
t = t->leftChild;
}
return t;
}
BSTNode<_Ty>* Max(BSTNode<_Ty>* t)const
{
while (t && t->rightChild != nullptr)
t = t->rightChild;
return t;
}
BSTNode<_Ty>* Parent(BSTNode<_Ty>* t, BSTNode<_Ty>* key)const
{
if (t == nullptr || key == t)
return nullptr;
if (key == t->leftChild || key == t->rightChild)
return t;
if (key->data < t->data)
return Parent(t->leftChild, key);
else if (key->data > t->data)
return Parent(t->rightChild, key);
}
BSTNode<_Ty>* Search(BSTNode<_Ty>* t, const _Ty& key)const
{
if (t == nullptr)
return t;
if (key < t->data)
return Search(t->leftChild, key);
else if (key > t->data)
return Search(t->rightChild, key);
return t;
}
private:
BSTNode<_Ty>* root;
};
int main()
{
vector<int> v1{53,78,17,45,23,9,65,87,81,94 };
BSTree<int> b1(v1);
b1.Insert(88);
b1.Order();
cout << endl;
b1.Remove(17);
b1.Remove(53);
b1.Order();
return 0;
}