二叉搜索树的定义
二叉搜索树的结构,查找元素是非常方便的,将大大减少遍历查找的时间复杂度,它是特殊的二叉树,所以它的定义和二叉树一样
typedef int D_TYPE;
typedef struct BSTree
{
struct BSTree* _Left;
struct BSTree* _Right;
D_TYPE data;
}BSTree,*pBSTree;
二叉搜索树增加元素
二叉搜索树的每个结点的数据,都比自己的左孩子大,比右孩子小。所以在增加元素的时候也必须遵循这个规则,元素增加代码如下:
bool BSTreeInsert(pBSTree* Bst,D_TYPE d)
{
pBSTree cur = *Bst;
pBSTree pre = NULL;
int ret;
assert(Bst);
if(NULL == *Bst)
{
*Bst = BuyBSTree(d);
return true;
}
else
{
while(cur)
{
pre = cur;
if(d < cur->data)
{
ret = 1;
cur = cur->_Left;
}
else if(d > cur->data)
{
ret = 0;
cur = cur->_Right;
}
else
return false;
}
if(1 == ret)
pre->_Left = BuyBSTree(d);
else
pre->_Right = BuyBSTree(d);
return true;
}
}
返回bool类型是为了判断是否增加成功,函数首先判断头结点指针是否为空,如果是空就得让头结点指向第一个创建的节点,这也是函数传参为什么传二级指针。如果头结点不为空,让cur走向循环,用pre保存cur,为了保存cur的前一个,最后找到位置的时候用pre->next来增加新元素。如果找到重复元素就返回失败。
二叉搜索树删除元素
删除元素也必须得遵循规则,增加元素无非就是找到增加的位置然后让上一个next指针指向他,但是删除元素删除之后会打破原本的二叉搜索树的结构,具体代码如下:
bool BSTreeErase(pBSTree* Bst,D_TYPE d)
{
pBSTree del = *Bst;
pBSTree pre = *Bst;
pBSTree cur = NULL;
assert(Bst);
if(NULL == *Bst)
return false;
while(del)
{
if(d == del->data)
break;
else if(d < del->data)
{
pre = del;
del = del->_Left;
}
else
{
pre = del;
del = del->_Right;
}
}
if(NULL == del)
return false;
if(NULL == del->_Left)
{
if(pre == del)
{
*Bst = del->_Right;
return true;
}
if(pre->_Left == del)
pre->_Left = del->_Right;
else
pre->_Right = del->_Right;
return true;
}
else if(NULL == del->_Right)
{
if(pre == del)
{
*Bst = del->_Left;
return true;
}
if(pre->_Left == del)
pre->_Left = del->_Left;
else
pre->_Right = del->_Left;
return true;
}
else
{
cur = del->_Right;
pre = del;
while(cur->_Left)
{
pre = cur;
cur = cur->_Left;
}
del->data = cur->data;
if(pre == del)
pre->_Right = cur->_Right;
else
pre->_Left = cur->_Right;
return false;
}
}
用第一个循环来找到需要删除的那个元素的节点,找不到就返回false。找到需要删除的结点之后,有三种情况:
1.只有右结点(或者是叶子节点)
如果只有右结点,要删除它,只需要让它的双亲节点,指向它的右结点,把它跳过去就行了。如图:
2.只有左结点
和上面的只有右结点同理,值得注意的是,这两个情况都有一个特殊可能就是,del就是二叉搜索树头结点所指向的结点,那么他是没有pre的。所以我们在函数一开始就将pre和del都赋值为头结点,所以当第一个循环结束,还检测到两个相等,就直接让头结点的指针指向del的Left或者Right。
3.左右节点都有
这是比较复杂的情况,解决方法是类似于替换法。就是将此节点右子树里面最小的元素值赋值给它(因为右子树都是大于它的,取最小元素才不会破坏右子树的结构),当然取左子树的最大的可以替换,这里以右子树的最小的为例,如图:
还有一个小问题就是del到底是pre的左孩子还是右孩子,需要用if去判断一下,大体思路是这样的,具体如何实现还得多调试完成。
递归完成基本操作
增加元素用递归完成代码:
bool BSTreeInsert_R(pBSTree* Bst,D_TYPE d)
{
assert(Bst);
if(NULL == *Bst)
{
*Bst = BuyBSTree(d);
return true;
}
else if(d == (*Bst)->data)
return false;
else if(d < (*Bst)->data)
return BSTreeInsert_R(&(*Bst)->_Left,d);
else
return BSTreeInsert_R(&(*Bst)->_Right,d);
}
删除元素用递归完成代码:
{
pBSTree cur;
assert(Bst);
if(NULL == (*Bst))
return false;
else if(d < (*Bst)->data)
return BSTreeErase_R(&(*Bst)->_Left,d);
else if(d > (*Bst)->data)
return BSTreeErase_R(&(*Bst)->_Right,d);
else
{
if(NULL == (*Bst)->_Left)
*Bst = (*Bst)->_Right;
else if(NULL == (*Bst)->_Right)
*Bst = (*Bst)->_Left;
else
{
cur = (*Bst)->_Right;
while(cur->_Left)
cur = cur->_Left;
(*Bst)->data = cur->data;
BSTreeErase_R(&(*Bst)->_Right,cur->data);
}
return true;
}
}