一、二叉排序树
1.1 二叉排序树的定义
二叉排序树,又称二叉查找树(BST,Binary Search Tree)具有如下性质的二叉树:
- 左子树上所有结点的关键字均小于根结点的关键字;
- 右子树上所有结点的关键字均大于根结点的关键字。
- 左子树和右子树又各是一棵二叉排序树;
- 左子树结点值 < 根结点值 < 右子树结点值;
- 进行中序遍历,可以得到一个递增的有序序列。
// 二叉排序树存储结构
typedef struct BSTNode{
int key;
struct BSTNode *lchild, *rchild;
}BSTNode, *BiTree;
1.2 二叉排序树的查找
【分析】: 1、如果树非空,k的值与根结点比较,如果相等则查找成功;2、k<根,在左子树上查找,否则在右子树上查找;3、查找成功,返回结点指针;查找失败则返回NULL。
// 在二叉排序树中查找值为key的结点
BSTNode *BST_Sreach(BiTree T, int key){
while(T!=NULL && key!=T->key){ //若树空或等于根结点值,则结束循环
if(key < T->key)
T = T->lchild; //小于,则在左子树上查找
else
T = T->rchild; //大于,则在右子树上查找
}
return T;
}
// 在二叉排序树中查找值为key的结点(递归实现)
BSTNode *BSTSreach(BiTree T, int key){
if(T=NULL)
return NULL; // 查找失败
if(key=T->key)
return T; // 查找成功
else if(key < T->key)
return BSTSreach(T->lchild, key); //在左子树找
else
return BSTSreach(T->rchild, key); //在右子树找
}
这两个算法,递归实现需要的最坏空间复杂度O(h);因此选用第一个算法为好。
1.3 二叉排序树的插入
【分析】:1、如果树为空,直接插入结点;2、若关键字k小于 根结点值,则插入到左子树;3、若关键字k大于根结点值,则插入到右子树。
插入的结点一定是一个新添加的叶结点,且是查找失败时的查找路径上访问的最后一个结点的左孩子或右孩子。
// 在二叉排序树插入关键字为k的新结点(递归实现)
int BST_Insert(BiTree &T, int k){
if(T=NULL){
T = (BiTree)malloc(sizeof(BSTNode));
T->key = k;
T->lchild = T->rchild = NULL;
return 1; //返回1,插入成功
}
else if(k==T->key)
return 0;
else if(k<T->key)
return BST_Insert(T->lchild,k);
else
return BST_Insert(T->rchild,k);
}
1.4 二叉排序树的构建
从一棵空树出发, 依次输入元素,将它们插入二叉排序树中的合适位置。设查找的关键字序列为{45, 24, 53, 45, 12, 24},则生成的二叉排序树如图所示。
[分析]:开始令树为空,while循环插入操作,i计数知道插入的总数
// 按照str[]中的关键字序列建立二叉排序树
void Creat_BST(BSTree &T,int str[],int n){
T=NULL; //初始时T为空树
int i=0;
while(i<n){ // 依次将每个关键字插入到二叉排序树中
BST_Insert(T,str[i]); // 进行插入
i++;
}
}
不同的关键字序列可能得到同款二叉排序树,也可能得到不同款二叉排序树。
1.5 二叉排序树的删除
在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。删除操作的实现过程按3种情况来处理:
先搜索找到目标结点:
- ① 若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质。
- ② 若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。
- ③ 若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。
z的后继:z的右子树中最左下结点(该节点一定没有左子树)。
z的前驱:z的左子树中最右下结点(该节点一定没有右子树)
1.6 查找效率分析
查找长度——在查找运算中,需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度。
二叉排序树的查找效率,主要取决于树的高度。若二叉排序树的左、右子树的高度之差的绝对值不超过1,则这样的二叉排序树称为平衡二叉树,它的平均查找长度为O(logn)。
若二叉排序树是一个只有右(左)孩子的单支树(类似于有序的单链表),则其平均查找长度为O(n)。在最坏情况下,即构造二叉排序树的输入序列是有序的,则会形成一个倾斜的单支树,此时二叉排序树的性能显著变坏,树的高度也增加为元素个数n,如图右所示。
查找成功的平均查找长度 ASL(Average Search Length)
图(左):ASL = (1*1 + 2*2 + 3*4 + 4*1)/8 = 2.625
图(右):ASL = (1*1 + 2*2 + 3*1 + 4*1 + 5*1 + 6*1+ 7*1)/8 = 3.75
查找失败的平均查找长度 ASL(Average Search Length)
图(左):ASL = (3*7+4*2)/9 = 3.22
图(右):ASL = (2*3+3+4+5+6+7*2)/9 = 4.22