持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
树型查找——二叉排序树
二叉排序树定义:
二叉排序树(也称二叉查找树)或者是一棵空树,或者是具有下列特性的二叉树:
1)若左子树非空,则左子树上所有结点的值均小于根结点的值。
2若右子树非空,则右子树上所有结点的值均大于根结点的值。
3左、右子树也分别是一棵二叉排序树。
根据二叉排序树的定义,左子树结点值<根结点值<右子树结点值,所以对二叉排序树进行中序遍历,可以得到一个递增的有序序列。
二叉排序树的查找:
二叉排序树的查找是从根结点开始,沿某个分支逐层向下比较的过程。若二叉排序树非空,先将给定值与根结点的关键字比较,若相等,则查找成功;若不等,如果小于根结点的关键字,则在根结点的左子树上查找,否则在根结点的右子树上查找。这显然是一个递归的过程。
二叉排序树的非递归查找算法:
BSTNode *BST_Search(BiTree T,ElemType key){
while(T!=NULL && key!=T->data){
if(key < T->data){
T = T->lchild;
}else{
T = T->rchild;
}
}
return T;
}
二叉排序树的插入
二叉排序树作为一种动态树表,其特点是树的结构通常不是一次生成的,而是在查找过程中,当树中不存在关键字值等于给定值的结点时再进行插入的。
插入结点的过程如下:若原二叉排序树为空,则直接插入结点:否则,若关键字k小于根结点值,则插入到左子树,若关键字k大于根结点值,则插入到右子树。插入的结点一定是一个新添加的叶结点,且是查找失败时的查找路径上访问的最后一个结点的左孩子或右孩子。
二叉排序树插入操作的算法如下:
int BST_Insert(BiTree &T,KeyType k){
if(T==NULL){
T=(BiTree)malloc(sizeof(BSTNode));
T->data=k;
T->lchild=T->rchild=NULL;
return 1;
}else if(k==T->data){
return 0;
}else if(k<T->data){
return BST_Insert(T->lchild,k);
}else{
return BST_Insert(T->rchild,k);
}
}
二叉排序树的构造
从一棵空树出发,依次输入元素,将它们插入二叉排序树中的合适位置。
算法如下:
void Creat_BST(BiTree &T,KeyType str[],int n){
T=NULL;
int i=0;
while(i<n){
BST_Insert(T,str[i]);
i++;
}
}
二叉排序树的删除
在二叉排序树中删除一个结点时,不能把以该结点为根的子树上的结点都删除,必须先把被删除结点从存储二叉排序树的链表上摘下,将因删除结点而断开的二叉链表重新链接起来,同时确保二叉排序树的性质不会丢失。删除操作的实现过程按3种情况来处理:
- ①若被删除结点z是叶结点,则直接删除,不会破坏二叉排序树的性质。
- ②若结点z只有一棵左子树或右子树,则让z的子树成为z父结点的子树,替代z的位置。
- ③若结点z有左、右两棵子树,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一或第二种情况。
算法如下:
BiTree* Delete(BiTree* T, int x){
BinaryTreeNode* tmp;
if(!T) printf("not found\n");
else if(x < T->data)
T->lchild = Delete(T->lchild, x);
else if(x > T->data)
T->rchild = Delete(T->rchild, x);
else{
if( T->lchild && T->rchild){
tmp = *BST_Search(T->rchild);
T->data = tmp->data;
T->rchild = Delete(T->rchild, T->data);
}
else{
if(!T->lchild)
T = T->rchlid;
else if(!T->rchild)
T = T->lchild;
}
}
return T;
}