什么是二叉搜索树
二叉搜索树(BST)也称为二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质。
- 非空左子树的键值小于其根结点的键值。
- 非空右子树的键值大于其根结点的键值。
- 左右子树都是二叉搜索树。
二叉搜索树的查找操作
查找从根结点开始,如果树为空,返回NULL。
若树非空,则根结点关键字和X进行比较,并进行处理:
- 若X小于根结点的值,只需要在左子树中继续搜索。
- 若X大于根结点的值,在右子树中继续搜索。
- 若两者比较结果相等,搜索完成,返回指向此结点的指针。
Position Find ( ElementType X, BinTree BST )
{
if( !BST ) return NULL;//查找失败
if( X > BST->Data )//如果X大于根结点的值,到右子树中查找
return Find( X, BST->Right );
else if ( X < BST->Data )//否则,在左子树中查找
return Find( X, BST->Left );
else//如果相等,则查找成功,返回结点的地址
return BST;
}
上述代码是用尾递归(在程序分支的最后进行递归),效率不高。从编译的角度讲,尾递归都是可以用循环来实现的。所以,可将尾递归改为迭代函数。
Position IterFind( ElementType X, BinTree BST )
{
while( BST ){
if( X > BST->Data )
BST=BST->Right;
else if ( X < BST-> Data )
BST=BST->Left;
else
return BST;
}
return NULL;
}
查找最大和最小值
最大元素一定是在树的最右分支的端结点上
最小元素一定是在树的最左分支的端结点上
//查找最小值的递归算法
Position FindMin( BinTree BST )
{
if( !BST ) return NULL;//空的二叉树返回NULL
if( !BST->Left ){//找到最左结点并返回
return BST;
}else{//如果存在左孩子就继续查找
return FindMin( BST->Left );
}
}
//查找最大值的迭代算法
Position FindMax( BinTree BST )
{
if( BST )//一直向右查找
while( BST->Right ) BST = BST->Right;
return BST;
}
二叉搜索树的插入
BinTree Insert( ElementType X, BinTree BST )
{
if( !BST ){
//若原树为空,则生成并返回一个节点的二叉树
BST = malloc(sizeof(struct TreeNode));
BST->Data=X;
BST->Left=BST->Right=NUll;
}else{//开始找插入元素的位置
if( X<BST->Data )//递归插入到左子树
BST->Left = Insert( X,BST->Left );
else if( X>BST->Data )//递归插入到右子树
BST->Right = Insert( X,BST->Right );
//else x存在,什么也不做
return BST;
}
}
二叉搜索树的删除
有三种情况
- 要删除的是叶结点:直接删除,并修改其父结点指针—置为NULL
- 要删除的结点只有一个孩子结点:将其父结点的指针指向要删除结点的孩子结点。
- 要删除的结点有左、右两棵子树:用另一结点替代被删除的结点:右子树的最小元素,或者左子树的最大元素。
BinTree Delete( ElementType X, BinTree BST )
{
Position Tmp;
if( !BST ) printf("要删除的元素未找到");
else if( X < BST->Data )//如果小于根结点元素,左子树递归
BST->Left = Delete( X, BST->Left );
else if( X > BST->Data )//大于根结点元素,右子树递归
BST->Right = Delete( X, BST->Right );
else{/*找到了要删除的结点*/
if( BST->Left && BST->Right){//被删除的结点有左右两个子结点
Tmp = FindMin( BST->Right );//在右子树中找到最小的元素替换要删除的结点
BST->Data = Tmp->Data;
BST->Right = Delete( BST->Data, BST->Right );//删除右子树中那个最小的元素
} else {//被删除的结点有一个或无子结点
Tmp = BST;
if( !BST->Left );//有右孩子,或无子结点
BST = BST->Right;
else if( !BST->Right )//有左孩子或无子结点
BST = BST->Left;
free( Tmp );
}
}
return BST
}