二叉搜索树
1. 二叉搜索树的概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 并且它的左右子树也分别为二叉搜索树
图例:
2.二叉搜索树的创建,插入,查找,删除
2.1 创建
二叉搜索树的创建,等同于二叉树的创建过程,区别是,在插入的过程需要进行数值
大小比较,把节点放在它最合适的地方,保证插入后,二叉搜索树的中序遍历结果是有序
的即可。
如果是空树,就将插入的节点作为根节点。如果不是空树,就和根节点进行比较,比根
节点中的值小,就到根的左孩子中寻找,比根节点值大的就去根的右孩子中寻找。如果在
查找过程中,遇到了相同的元素,就可以直接返回(本题中只考虑插入不同的元素),当
遇到空节点的时候说明位置找到了,即可插入。
创建和插入的代码:
//插入数据,已有的数据不会重复插入
bool Insert(const T& data)
{
//如果是空树,将要插入的将数据作为根节点
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
//如果不是空树,查找要插入的位置
PNode pCur = _pRoot;
PNode pParent = nullptr;
while (pCur)
{
pParent = pCur;
if (data < pCur->_data)
pCur = pCur->_pLeft;
else if (data > pCur->_data)
pCur = pCur->_pRight;
else
return false;
}
//走到这里,说明二叉树中没有要插入的重复数据,就可以插入节点
pCur = new Node(data);
if (data < pParent->_data)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
return true;
}
2.2查找
包括查找某个特定值的节点,查找最右边的节点,查找最左边的节点。
方法:先与根节点内容比较,在根据大小关系在子树中进行查找。最左边的节点
也就是值最小的节点。最右边的节点是值最大的节点。
代码如下:
//获取最左边的节点
PNode MostLeft()
{
if (_pRoot == nullptr)
return nullptr;
PNode pCur = _pRoot;
while (pCur->_pLeft)
{
pCur = pCur->_pLeft;
}
return pCur;
}
//获取最右边的节点
PNode MostRight()
{
if(_pRoot == nullptr)
return nullptr;
PNode pCur = _pRoot;
while (pCur->_pRight)
{
pCur = pCur->_pRight;
}
return pCur;
}
//查找二叉搜索树中的节点
PNode Find(const T& data)
{
PNode pCur = _pRoot;
while (pCur)
{
if (pCur->_data == data)
return pCur;
else if (data > pCur->_data)
pCur = pCur->_pRight;
else
pCur = pCur->_pLeft;
}
return nullptr;
}
2.3删除二叉搜索树的节点
删除节点是二叉搜索树相关内容中较为复杂的内容,以图示意。
代码如下:
//删除节点
bool Erase(const T& data)
{
//找待删除的节点
PNode pCur = _pRoot;
PNode pParent = nullptr;
PNode AlterNode = nullptr;
while (pCur)
{
if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (data > pCur->_data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
//找到节点
else
{
if (pCur->_pLeft == nullptr) //要删除的节点只有右孩子 或者 是叶子结点都能进入
{
if (pParent->_pRight == pCur) //要删除的节点是双亲节点的右孩子
{
pParent->_pRight = pCur->_pRight;
delete pCur;
}
else //要删除的节点(该节点只有右孩子的同时)是双亲节点的左孩子
{
pParent->_pLeft = pCur->_pRight;
delete pCur;
}
return true;
}
else if (pCur->_pRight == nullptr)
{
//要删除的节点 只有左孩子
pParent->_pRight = pCur->_pLeft;
delete pCur;
return true;
}
else
{
//要删除的节点是 左右孩子都有
//先找到右子数中的最小的节点
AlterNode = pCur;
pParent = nullptr;
AlterNode = pCur->_pRight;
while (AlterNode->_pLeft)
{
pParent = AlterNode;
AlterNode = AlterNode->_pLeft;
}
pCur->_data = AlterNode->_data;
pParent->_pLeft = AlterNode->_pLeft;
delete AlterNode;
return true;
}
}
}
return false;
}
——————————————————————————————————
二叉搜索树总体代码:
#pragma once
#include<iostream>
using namespace std;
template <class T>
struct BSTNode
{
BSTNode(const T& data)
:_pLeft(nullptr)
, _pRight(nullptr)
, _data(data)
{}
BSTNode<T>* _pLeft;
BSTNode<T>* _pRight;
T _data;
};
template<class T>
class BSTree
{
typedef BSTNode<T> Node;
typedef BSTNode<T>* PNode;
public:
BSTree()
:_pRoot(nullptr)
{}
//插入数据,已有的数据不会重复插入
bool Insert(const T& data)
{
//如果是空树,将要插入的将数据作为根节点
if (_pRoot == nullptr)
{
_pRoot = new Node(data);
return true;
}
//如果不是空树,查找要插入的位置
PNode pCur = _pRoot;
PNode pParent = nullptr;
while (pCur)
{
pParent = pCur;
if (data < pCur->_data)
pCur = pCur->_pLeft;
else if (data > pCur->_data)
pCur = pCur->_pRight;
else
return false;
}
//走到这里,说明二叉树中没有要插入的重复数据,就可以插入节点
pCur = new Node(data);
if (data < pParent->_data)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
return true;
}
//获取最左边的节点
PNode MostLeft()
{
if (_pRoot == nullptr)
return nullptr;
PNode pCur = _pRoot;
while (pCur->_pLeft)
{
pCur = pCur->_pLeft;
}
return pCur;
}
//获取最右边的节点
PNode MostRight()
{
if(_pRoot == nullptr)
return nullptr;
PNode pCur = _pRoot;
while (pCur->_pRight)
{
pCur = pCur->_pRight;
}
return pCur;
}
//中序遍历
void InOrder()
{
_InOrder(_pRoot);
}
//销毁二叉搜索树
void Destroy(PNode& pRoot)
{
if (_pRoot == nullptr)
return ;
else
Destroy(pRoot->_pLeft);
Destroy(pRoot->_pRight);
delete pRoot;
pRoot = nullptr;
}
//删除节点
bool Erase(const T& data)
{
//找待删除的节点
PNode pCur = _pRoot;
PNode pParent = nullptr;
PNode AlterNode = nullptr;
while (pCur)
{
if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (data > pCur->_data)
{
pParent = pCur;
pCur = pCur->_pRight;
}
//找到节点
else
{
if (pCur->_pLeft == nullptr) //要删除的节点只有右孩子 或者 是叶子结点都能进入
{
if (pParent->_pRight == pCur) //要删除的节点是双亲节点的右孩子
{
pParent->_pRight = pCur->_pRight;
delete pCur;
}
else //要删除的节点(该节点只有右孩子的同时)是双亲节点的左孩子
{
pParent->_pLeft = pCur->_pRight;
delete pCur;
}
return true;
}
else if (pCur->_pRight == nullptr)
{
//要删除的节点 只有左孩子
pParent->_pRight = pCur->_pLeft;
delete pCur;
return true;
}
else
{
//要删除的节点是 左右孩子都有
//先找到右子数中的最小的节点
AlterNode = pCur;
pParent = nullptr;
AlterNode = pCur->_pRight;
while (AlterNode->_pLeft)
{
pParent = AlterNode;
AlterNode = AlterNode->_pLeft;
}
pCur->_data = AlterNode->_data;
pParent->_pLeft = AlterNode->_pLeft;
delete AlterNode;
return true;
}
}
}
return false;
}
PNode Find(const T& data)
{
PNode pCur = _pRoot;
while (pCur)
{
if (pCur->_data == data)
return pCur;
else if (data > pCur->_data)
pCur = pCur->_pRight;
else
pCur = pCur->_pLeft;
}
return nullptr;
}
private:
void _InOrder(PNode pRoot)
{
if (pRoot)
{
_InOrder(pRoot->_pLeft);
cout << pRoot->_data<<" ";
_InOrder(pRoot->_pRight);
}
}
private:
PNode _pRoot;
};
void TestBSTree()
{
int array[] = { 5,2,3,7,6,4,9,1,8,0 };
BSTree<int> t;
for (auto e : array)
t.Insert(e);
t.InOrder();
cout << endl;
t.Erase(9);
t.InOrder();
cout << endl;
t.Erase(3);
t.InOrder();
cout << endl;
t.Erase(0);
t.InOrder();
cout << endl;
t.Erase(5);
t.InOrder();
cout << endl;
t.Erase(1);
t.InOrder();
cout << endl;
}
运行结果: