一、概念
二叉搜索树(Binary Search Tree)又称:二叉排序树。这棵树要么是一颗空树,要么是一颗具有以下性质的树:
1.若它的左子树不为空,则所有左子树上的值均小于其根节点的值;
2.若它的右子树不为空,则所有右子树上的值均大于其根节点得值;
3.它的左右子树也分别为二叉搜索树。
例如:int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
二、操作
二叉搜索树有搜索、插入、删除三种操作。
1.搜索
搜索时分两种情况:
(1)若树不为空(根节点不为空),如果要查找的节点key==根节点key,返回true;
如果要查找的节点key<根节点key,则在其左子树中查找;
如果要查找的节点key>根节点key,则在其右子树中查找;
(2)否则,返回false。
对于上述几种情况,根据上图(树不为空),我们来举几个例子。
(1)查找根节点:5
(2)查找左子树(有三种情况:查找左子树1、查找左子树1中的右子树2、查找左子树0的左子树-1(-1不存在,为空))
(3)查找右子树(有三种情况:查找右子树7的左子树6、查找右子树8、查找右子树9的右子树10(10不存在,为空))
代码实现如下:
bool Find(const K& key)
{
PNode pCur = _pRoot;
while (pCur)
{
if (key == pCur->_key)
return true;
else if (key < pCur->_key)
pCur = pCur->_pLeft;
else
pCur = pCur->_pRight;
}
return false;
}
2.
插入
在二叉搜索树中插入一个新元素时,首先分两种情况:
(1)若树为空,直接插入,返回true(插入的元素就是根节点);
(2)若树不为空,则要进行检验该元素树中是否存在,如果搜索成功,则说明要插入的元素树中已经存在,则该 元素不能插入,否则,将新元素插入到搜索停止的地方。
对于上述几种情况,我们也举几个简单的例子。
(1)树为空,直接插入新元素5(说明:插入任何新元素都可以,这里插入5的原因是为了保持整个博客所用的是 同一棵树,这棵树的根节点是5)
(2)树不为空,在树的左子树中插入已存在元素1、插入已存在元素4(左子树中的右子树),同理,可以在树的 右子树进行已存在元素的插入。
(3)树不为空,在树的右子树中插入新元素5.5(右子树中的左子树),插入新元素10,同理,可以在树的左子树 中进行树中不存在的新元素的插入操作。
代码实现如下:
bool Insert(const K& key, const V& value)
{
//若树为空
if (_pRoot == NULL)
{
_pRoot = new Node(key, value);
return true;
}
//若树不空,找待插结点的位置
PNode pParent = NULL;
PNode pCur = _pRoot;
while (pCur)
{
if (_pRoot->_key == key)
return false;
else if (_pRoot->_key > key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//插入新节点
PNode pNewNode = new Node(key, value);
if (key < pParent->_key)
pParent->_pLeft = pNewNode;
else
pParent->_pRight = pNewNode;
return true;
}
3.
删除
二叉搜索树的删除操作是最难得一种操作,但是只要我们捋清楚其中的情况,针对每一种情况知道怎么删除也会发现其实并不是特别难哦!
(1)若树为空,直接返回false;
(2)若树不为空-->要删除的节点不在树内,直接返回false;
-->要删除的节点在树内,有四种情况:
1)要删除的节点左右孩子都不存在:直接删除该节点
2)要删除的节点只有左孩子:删除该节点且使被删除节点的双亲指向被删除节点的左孩子
3)要删除的节点只有右孩子:删除该节点且使被删除节点的双亲指向被删除节点的右孩子
4)要删除的节点左右孩子均存在:在该右子树中寻找中序遍历下的第一个节点(即关键码最 小的节点),用该节点的值替换要删除节点的位置,然后 处理该节点的删除问题。
说明:情况1可以结合到情况2或者情况3中处理。
对于上述情况,我们来举几个例子。
(1)左右孩子均不存在:以节点2为例
这种情况也可以看成只有左子树,如下图
(2)要删除的节点只有右子树:以节点8为例
(3)要删除的节点左右孩子均存在:以节点5、节点7为例
代码实现如下:
bool Delete(const K& key, const V& value)
{
//若树为空
if (NULL == _pRoot)
return false;
//找待删除结点的位置
PNode pCur = _pRoot;
PNode pParent = NULL;
while (pCur)
{
if (key == pCur->_key)
break;
else if (key < pCur->_pLeft)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
if (pCur)
{
//当前节点不为空,左子树为空
if (NULL == pCur->_pLeft)
{
if (pCur == _pRoot)
_pRoot = _pRoot->_pRight;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pRight;
else
pParent->_pRight = pCur->_pRight;
}
}
//右子树为空
else if (NULL == pCur->_pRight)
{
if (pCur == _pRoot)
_pRoot = _pRoot->_pLeft;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pLeft;
else
pParent->_pRight = pCur->_pLeft;
}
}
else
{
//在右子树中找中序遍历下的第一个结点
PNode firstOFIn = pCur->_pRight;
while (firstOFIn->_pLeft)
{
pParent = firstOFIn;
firstOFIn = firstOFIn->_pLeft;
}
pCur->_key = firstOFIn->_key;
pCur->_value = firstOFIn->_value;
//删5 删7
if (firstOFIn == pParent->_pLeft)
pParent->_pLeft = firstOFIn->_pRight;
else
pParent->_pRight = firstOFIn->_pRight;
pCur = firstOFIn;
}
delete pCur;
}
return false;
}
到这里,二叉搜索树的三种操作就处理完了,下面附上整个过程的代码。
#include<iostream>
using namespace std;
#include<assert.h>
#include<stdlib.h>
template<class K,class V>
struct BSTNode
{
BSTNode(const K& key, const V& value)
: _pLeft(NULL)
, _pRight(NULL)
, _key(key)
, _value(value)
{}
BSTNode<K, V>* _pLeft;
BSTNode<K, V>* _pRight;
K _key;
V _value;
};
template<class K,class V>
class BSTree
{
typedef BSTNode<K, V> Node;
typedef Node* PNode;
public:
BSTree()
: _pRoot(NULL)
{}
//查找
bool Find(const K& key)
{
PNode pCur = _pRoot;
while (pCur)
{
if (key == pCur->_key)
return true;
else if (key < pCur->_key)
pCur = pCur->_pLeft;
else
pCur = pCur->_pRight;
}
return false;
}
//插入
bool Insert(const K& key, const V& value)
{
//若树为空
if (_pRoot == NULL)
{
_pRoot = new Node(key, value);
return true;
}
//若树不空,找待插结点的位置
PNode pParent = NULL;
PNode pCur = _pRoot;
while (pCur)
{
if (_pRoot->_key == key)
return false;
else if (_pRoot->_key > key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
//插入新节点
PNode pNewNode = new Node(key, value);
if (key < pParent->_key)
pParent->_pLeft = pNewNode;
else
pParent->_pRight = pNewNode;
return true;
}
//删除
bool Delete(const K& key, const V& value)
{
//若树为空
if (NULL == _pRoot)
return false;
//找待删除结点的位置
PNode pCur = _pRoot;
PNode pParent = NULL;
while (pCur)
{
if (key == pCur->_key)
break;
else if (key < pCur->_pLeft)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else
{
pParent = pCur;
pCur = pCur->_pRight;
}
}
if (pCur)
{
//当前节点不为空,左子树为空
if (NULL == pCur->_pLeft)
{
if (pCur == _pRoot)
_pRoot = _pRoot->_pRight;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pRight;
else
pParent->_pRight = pCur->_pRight;
}
}
//右子树为空
else if (NULL == pCur->_pRight)
{
if (pCur == _pRoot)
_pRoot = _pRoot->_pLeft;
else
{
if (pCur == pParent->_pLeft)
pParent->_pLeft = pCur->_pLeft;
else
pParent->_pRight = pCur->_pLeft;
}
}
else
{
//在右子树中找中序遍历下的第一个结点
PNode firstOFIn = pCur->_pRight;
while (firstOFIn->_pLeft)
{
pParent = firstOFIn;
firstOFIn = firstOFIn->_pLeft;
}
pCur->_key = firstOFIn->_key;
pCur->_value = firstOFIn->_value;
//删5 删7
if (firstOFIn == pParent->_pLeft)
pParent->_pLeft = firstOFIn->_pRight;
else
pParent->_pRight = firstOFIn->_pRight;
pCur = firstOFIn;
}
delete pCur;
}
return false;
}
//找最小的元素
K MinData()
{
assert(_pRoot);
PNode pCur = _pRoot;
while (pCur->_pLeft)
pCur = pCur->_pLeft;
return pCur->_key;
}
//找最大的元素
K MaxData()
{
assert(_pRoot);
PNode pCur = _pRoot;
while (pCur->_pLeft)
pCur = pCur->_pLeft;
return pCur->_key;
}
//中序遍历的结果
void InOder()
{
cout << "InOder:";
_InOder(_pRoot);
cout << endl;
}
void _InOder(PNode pRoot)
{
if (pRoot)
{
_InOder(pRoot->_pLeft);
cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;
_InOder(pRoot->_pRight);
cout << "<" << pRoot->_key << "," << pRoot->_value << ">" << endl;
}
}
private:
PNode _pRoot;
};
void TextBST()
{
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
BSTree<int, int>bst;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
bst.Insert(a[i], i);
}
cout << bst.MaxData() << endl;
cout << bst.MinData() << endl;
bst.InOder();
}