概念:
二叉搜索树:又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
1、若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2、若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3、它的左右子树也分别为二叉搜索树
如下图:
二叉树基本操作
1. 插入:
在二叉查找树中插入新结点,要考虑以下步骤:
1.若二叉查找树root为空,则新结点为根;
2.若二叉查找树root不为空,则应该寻找插入点并返回它的地址(若新结点中的关键字已经存在,则返回空指针);
3.若新结点的关键字小于插入点的关键字,则将新结点插入到插入点的左子树中,大于则插入到插入点的右子树中。
2. 查找
看key值,key值比当前结点值大在右中找,否则在左中查找。
3. 删除
删除分为几种情况
由此 我们可以写出代码:
template <class K,class V>
struct BSTNode
{
BSTNode<K, V>* _pLeft;
BSTNode<K, V>* _pRight;
K _key;
V _value;
BSTNode(const K& key, const V& value)
: _pLeft(NULL)
, _pRight(NULL)
, _key(key)
, _value(value)
{}
};
template<class K,class V>
struct BinaryTreeSearch
{
typedef BSTNode<K, V> Node;
public:
BinaryTreeSearch()
:_pRoot(NULL)
{}
void Insert(const K& key, const V& value)
{
//头结点是空
if (NULL == _pRoot)
{
_pRoot = new Node(key, value);
return ;
}
Node* pCur = _pRoot;
Node* pParent = NULL;
//找插入位置
while (pCur)
{
if (key > pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else if (key <= pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
}
//插入元素
if (key < pParent->_key)
pParent->_pLeft = new Node(key, value);
else
pParent->_pRight = new Node(key,value);
}
bool Find(const K& key)
{
Node* pCur = _pRoot;
//找插入位置
while (pCur)
{
if (key > pCur->_key)
{
pCur = pCur->_pRight;
}
else if (key < pCur->_key)
{
pCur = pCur->_pLeft;
}
else
return true;
}
return false;
}
bool Remove(const K& key)
{
Node* pCur = _pRoot;
Node* pParent = NULL;
//找位置
while (pCur && pCur->_key != key)
{
if (key > pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else if (key <= pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
}
if (pCur)
{
if (pCur != _pRoot && pCur->_pLeft == NULL || pCur->_pRight == NULL)
{
if (pCur->_pLeft == NULL)
{
if (pParent->_pLeft == pCur)
pParent->_pLeft = pCur->_pRight;
else
pParent->_pRight = pCur->_pRight;
delete pCur;
}
else if (pCur->_pRight == NULL)
{
if (pParent->_pRight = pCur)
pParent->_pRight = pCur->_pLeft;
else
pParent->_pLeft = pCur->_pLeft;
delete pCur;
}
}
//如果这个节点左右都有孩子 此时应该找右边子树的最小结点 (即右子树最左边的结点)
else
{
Node* pFirstInorder = pCur->_pRight;
while (pFirstInorder->_pLeft)
{
pParent = pFirstInorder;
pFirstInorder = pFirstInorder->_pLeft;
}
pCur->_key = pFirstInorder->_key;
pCur->_value = pFirstInorder->_value;
//如果不是右单只 说明pParent左有元素
if (pParent->_pLeft == pFirstInorder)
pParent->_pLeft = pFirstInorder->_pRight;
else//是右单只
pParent->_pRight = pFirstInorder->_pRight;
pCur = pFirstInorder;
delete pCur;
}
}
if (pCur == NULL)
return false;
return true;
}
private:
Node* _pRoot;
};
void Funtest()
{
BinaryTreeSearch<int, int> bt;
int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
bt.Insert(5, 5);
bt.Insert(3, 3);
bt.Insert(4, 4);
bt.Insert(1, 1);
bt.Insert(7, 7);
bt.Insert(8, 8);
bt.Insert(2, 2);
bt.Insert(6, 6);
bt.Insert(0, 0);
bt.Insert(9, 9);
cout << bt.Find(1) << endl;
cout << bt.Find(111) << endl;
bt.Remove(3);
}
二叉搜索树的性能分析:
插入和删除操作的主体部分是查找,查找效率代表了二叉排序中上各个操作的性能。对有n个结点的二叉排序树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多
C(i)为查找到第i个数据元素时关键字的比较次数。
最好情况当二叉搜索树是完全二叉树时。
最坏情况当二叉搜索树是一支基本有序的单支二叉搜索树时。
因此最坏情况下,二叉排序树的平均查找长度为O(n),一般情况下平均查找长度为O(logn)。