树(中)
1.二叉搜索树:
二叉搜索树也称二叉排序树或二叉查找树,它是一种对排序和查找都很有用的特殊二叉树。
它可以为空,若不为空则会满足以下性质:
(1)非空左子树的所有键值小于其根结点的键值。
(2)非空右子树的所有键值大于其根结点的键值。
(3)左、右子树都是二叉搜索树。
二叉搜索树的查找
void find(struct tree *root,int x)
{
while(root!=NULL)
{
if(x>root->data)
root=root->r;//向右子树中移动,继续查找
else if(x<root->data)
root=root->l;//向左子树中移动,继续查找
else
break;
}
return root;
}
查找最大和最小元素:
根据性质可以知道:最大元素一定是在树的最右分枝的端结点上 ; 最小元素一定是在树的最左分枝的端结点上。
2.二叉搜索树的插入:
思路:将元素X插入二叉搜索树中关键是要找到元素应该插入的位置。位置的确定可以利用与上面的查找函数Find类似的方法,如果在树中找到X,说明要插入的元素已存在,可放弃插入操作。如果没找到X,查找终止的位置就是X应插入的位置。
struck tree Insert(struck tree root, int X )
{
if( root==NULL ) //若原树为空,生成并返回一个结点的二叉搜索树
{
root= (struck tree )malloc(sizeof(struck tree));
root->data = X;
root->l = root->r = NULL;
}
else//开始找要插入元素的位置
{
if( X <root->data )
root->l = Insert( root->l, X );//递归插入左子树
else if( X > root->data )
root->r = Insert( root->r, X ); //递归插入右子树
}
return root;
}
3.二叉搜索树的删除:
通常分为三种情况:
(1)要删除的是叶结点——可以直接删除,然后再修改其父结点的指针。
(2)要删除的结点只有一个孩子结点——删除之前需要改变其父结点的指针,指向要删除结点的孩子结点。
(3)要删除的结点有左、右两棵子树——为了保持二叉搜索树的有序性,替代被删除的元素的位置可以有两种选择:一种是取其右子树中的最小元素;另一个是取其左子树中的最大元素。
struct tree Delete(struct tree root,int X )
{ Position T;
if(root==NULL)
printf("要删除的元素未找到");
else
{
if(X<root->data)
root->l=Delete(root->l,X); // 从左子树递归删除
else if(X>root->data)
root->r=Delete(root->r,X); //从右子树递归删除
else // BST就是要删除的结点
{
//如果被删除结点有左右两个子结点
if(root->l&&root->r)
{
T=FindMin(root->r); //从右子树中找最小的元素填充删除结点
root->data=T->data;//从右子树中删除最小元素
root->r=Delete(root->r,root->data);
}
else //被删除结点有一个或无子结点
{
T=root;
if(!root->l)
root=root->r; //只有右孩子或无子结点
else
root=root->l; //只有左孩子
free(T);
}
}
}
return root;
4.平衡二叉树:
对于二叉树中任一结点T,其“平衡因子”定义为BF(T) = hL-hR,其中hL和hR分别为T的左、右子树的高度。任一结点左、右子树高度差的绝对值不超过1。即|BF(T) |≤ 1。
(1)RR: 首个不平衡的“发现者”(未必是根结点),它是调整起点位置。而“麻烦结点”在发现者右子树的右边,因而叫 RR 插入,需要RR 旋转(右单旋);
(2)LL: 首个“发现者”; “麻烦结点” 在发现者左子树的左边,因而叫 LL 插入;
(3)LR: 首个“发现者”; “麻烦结点”在左子树的右边,因而叫 LR 插入;