概念
二叉搜索树:它是一棵空树,或者具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上的所有结点的值都小于根节点的值
- 若它的右子树不为空,则右子树上的所有结点的值都小于根节点的值
- 它的左右子树也分别为二叉搜索树
操作
1.查找
2.插入
a. 若树为空,直接插入数据
b.若树不为空,按照二叉搜索树的性质查找插入位置,插入新结点
3.删除
若要删除的结点不存在,则返回,若存在,则分为以下几种情况:
a.要删除的结点没有孩子
b.要删除的结点没有左孩子
c.要删除的结点没有右孩子
d.要删除的结点有左右孩子
因为删除结点的本质是:让待删除结点的双亲指向待删除结点的左孩子或着右孩子
所以,可将a,b或者a,c情况结合,删除过程中的实际操作为:
情况1:删除该结点,使该结点的双亲结点指向被删除结点的左孩子
情况2:删除该结点,使该结点的双亲结点指向被删除结点的右孩子
情况3:删除该结点,在它的右子树中找最小结点(在左子树中找最大结点),将最小结点的值填补到该结点,再删除最小结点。
代码
#include<iostream>
using namespace std;
template<class T>
struct BSTNode
{
BSTNode(const T &data = T())
: _pLeft(nullptr)
, _pRight(nullptr)
, _data(data)
{}
BSTNode<T> *_pLeft;
BSTNode<T> *_pRight;
T _data;
};
template<class T>
class BSTree
{
typedef BSTNode<T> Node;
public:
BSTree()
: _pRoot(nullptr)
{}
//在二叉树搜索树中插入元素,成功返回true,失败返回false
//这是比较简单的二叉搜索树,若元素已经存在,则不插入,返回false
bool Insert(const T &data)
{
//空树
if (nullptr == _pRoot)
{
_pRoot = new Node(data);
return true;
}
//非空
//1.按照二叉搜索树的查找特性,找到带插入节点在树中的位置
Node *pCur = _pRoot;
Node *pParent = nullptr;
while (pCur)
{
pParent = pCur;
if (data < pCur->_data)
pCur = pCur->_pLeft;
else if (data > pCur->_data)
pCur = pCur->_pRight;
else
return false;//元素已经存在,不必插入,返回false
}
//2.插入新的结点
pCur = new Node(data);
if (data < pParent->_data)
pParent->_pLeft = pCur;
else
pParent->_pRight = pCur;
return true;
}
bool Delete(const T& data)
{
if (nullptr == _pRoot)
return false;
//找到待删除结点的位置
Node *pCur = _pRoot;
Node *pParent = nullptr;
while (pCur)
{
if (data == pCur->_data)
break;
else if (data < pCur->_data)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
pParent = pCur;
pCur = pCur->_pRight;
}
if (nullptr == pCur)
return false;
//删除
Node *pDelNode = pCur;
if (nullptr == pCur->_pLeft)//叶子节点或者只有右孩子
{
if (nullptr == pParent)//若要删除的为根节点
_pRoot = pCur->_pRight;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pRight;
else
pParent->_pRight = pCur->_pRight;
}
}
else if (nullptr == pCur->_pRight)//只有左孩子
{
if (nullptr == pParent)//若要删除的结点为根节点
_pRoot = pCur->_pLeft;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pLeft;
else
pParent->_pRight = pCur->_pLeft;
}
}
else//左右孩子都存在
{
//可在左子树中找最大结点或者在右子树中找最小结点,本次采用在右子树中找最小结点
Node *pDel = pCur->_pRight;
pParent = pCur;
while (pDel->_pLeft)
{
pParent = pDel;
pDel = pDel->_pLeft;
}
pCur->_data = pDel->_data;
//删除替代结点pDel
if (pParent->_pLeft == pDel)
pParent->_pLeft = pDel->_pRight;
else
pParent->_pRight = pDel->_pRight;
pDelNode = pDel;
}
delete pDelNode;
return true;
}
Node *Find(const T &data)
{
Node *pCur = _pRoot;
while (pCur)
{
if (data == pCur->_data)
return pCur;
else if (data < pCur->_data)
pCur = pCur->_pLeft;
else
pCur = pCur->_pRight;
}
return nullptr;
}
Node *LeftMost()
{
if (nullptr == _pRoot)
return nullptr;
Node *pCur = _pRoot;
while (pCur->_pLeft)
{
pCur = pCur->_pLeft;
}
return pCur;
}
Node *RightMost()
{
if (nullptr == _pRoot)
return nullptr;
Node *pCur = _pRoot;
while (pCur->_pRight)
{
pCur = pCur->_pRight;
}
return pCur;
}
void InOrder()//进行一次封装,减少用户传参
{
_InOrder(_pRoot);
}
private:
void _InOrder(Node *pRoot)//中序遍历
{
if (pRoot)
{
_InOrder(pRoot->_pLeft);
cout << pRoot->_data << " ";
_InOrder(pRoot->_pRight);
}
}
private:
Node *_pRoot;
};
int main()
{
BSTree<int> a;
a.Insert(5);
a.Insert(3);
a.Insert(4);
a.Insert(1);
a.Insert(7);
a.Insert(8);
a.Insert(2);
a.Insert(6);
a.Insert(0);
a.Insert(9);
a.InOrder();
cout << endl;
a.Delete(8);
a.InOrder();
cout << a.Find(6) << endl;
cout << a.LeftMost()->_data << " " << a.RightMost()->_data << endl;
return 0;
}