一、二叉搜索树
1.定义
二叉搜索树BST
(1)非空左子树的所有键值小于根节点
(2)非空右子树的所有键值大于根节点
(3)左右子树都是二叉搜索树
2.二叉搜索树的查找
(1)Find函数
Position Find(ElementType x, BinTree BST)
{
if(!BST) return NULL; //查找失败
if(x > BST->Data)
return Find(x, BST->Right);
else if(X < BST->Data)
return Find(x, BST->Left);
else
return BST;
}
以上的函数返回都是尾递归(即在函数返回时递归),一般尾递归都可用循环来实现
改为迭代函数:
Postion 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;
}
- 查找的效率取决于树的高度
(2)查找最大和最小元素
最大元素一定放在最右分枝的端结点上
最小元素一定放在最左分枝的端结点上
查找最小元素的递归函数:
//查找最小元素的递归函数
Position FindMin(BinTree BST)
{
if(!BST) return NULL;
else if(!BST->Left) //如果结点为空
return BST;
else
return FindMin(BST->Left);
}
查找最大元素的迭代函数:
//查找最大元素的迭代函数
Position FindMax(BinTree BST)
{
if(BST)
while(BST->Right) BST = BST->Right;
return BST;
}
3.二叉搜索树的插入
//二叉搜索树的插入
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->Date) //递归插入左子树
BST->Left = insert(X, BST->Left);
else if(X > BST->Date) //递归插入右子树
BST->Right = Insert(X, BST->Right)
//else X已存在,什么也不做
}
return BST;
}
4.二叉搜索树的删除
考虑三种情况
- 叶结点:直接删除,并修改其父结点指针——置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;
}
二、平衡二叉树
1.定义
-
平均查找长度ASL
-
平衡因子(balance Factor):BF(T) = hL-hR
-
平衡二叉树(AVL树):
(1)空树,或者
(2)任意结点左、右子树高度差的绝对值不超过1,即|BF(T)|<=1
-
h层的平衡二叉树至少有
n(h) = F(h+2)-1
个结点(F为斐波拉契数列)
-
给定结点数为n的AVL树的最大高度为O(log2n),即查找效率
2.平衡二叉树的调整
- 右单旋(右子树的右子树上)
注意: BL的位置
它一定比A大,比B小
- 左单旋(左子树的左子树)
- LR旋转(左子树的右子树)
需要调整的是May,Aug,Mar:
让中间值Mar作为最上层的结点
- RL旋转(右子树的左子树)
此部分代码如下:
//AVL树的旋转与插入
typedef struct AVLNode *Position;
typedef Position AVLTree; //AVL树类型
struct AVLNode{
ElementType Data; //结点数据
AVLTree Left; //左子树
AVLTree Right; //右子树
int Height; //树高
};
int Max(int a, int b)
{
return a > b ? a : b;
}
AVLTree SingleLeftRotation(AVLTree A)
{ //A必须有一个左子结点B
//将A与B做左单旋,更新A与B的高度,返回新根结点B
AVLTree B = A->Left;
A->Left = B->Right;
B->Right = A;
A->Height = Max(GetHeight(A->Left), GetHeight(A->Right))+1;
B->Height = Max(GetHeight(B->Left), A->Height)+1;
return B;
}
AVLTree DoubleLeftRightRotation(AVLTree A)
{
//A必须有一个左子结点B,且B必须有一个右子结点C
//将A、B与C做两次单旋,返回新根结点C
//将B和C做右单旋,C被返回
A->Left = SingleRightRotation(A->Left;)
//将A和C做左单旋,C被返回
return SingleLeftRotation(A);
}
AVLTree Insert(AVLTree T, ElementType X)
{
if(!T){ //若插入空树,则新建包含一个结点的树
T = (AVLTree)malloc(sizeof(struct AVLNode));
T->Data = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
else if(X < T->Data){
//插入T的左子树
T->Left = Insert(T->Left, X);
//如果需要左旋
if(GetHeight(T->Left) - GetHeight(T->Right) == 2)
if(X <T->Left->Data)
T = SingleLeftRotation(T); //左单旋
else
T = DoubleLeftRightRotation(T); //左-右双旋
}
else if(X > T->Data){
//插入T的右子树
T->Right = Insert(T->Right, X);
//如果需要右旋
if(GetHeight(T->Left) - GetHeight(T->Right == -2))
if(X > T->Right->Data)
T = SingleRightRotation(T); //右单旋
else
T= DoubleRightLeftRotation(T); //右-左双旋
}
//else X = =T->Data,无需插入操作
//更新树高
T->Height = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1;
return T;
}