一、定义
二叉排序树又称二叉搜索树,它或者是一棵空树,或者是具有以下性质的二叉树。
- 若它的左子树不为空,则左子树上所有结点的值均小于它根结点的值。
- 若它的右子树不为空,则右子树上所有结点的值均大于它根结点的值。
- 它的左右子树也为分别为二叉排序树。
二、二叉排序树的查找
算法思路:
1、比较当前需要查找的key值是否为根结点的值,如果是,则将根结点返回;
2、当前key值比根结点的值小,则递归查找根结点的左孩子;
3、当前key值比根结点的值大,则递归查找根结点的右孩子;
4、重复2-3,直到找到等于key值的结点,或者所有结点都找完了都不存在等于key值的结点。
//1.二叉排序树--查找
Status SearchBST(BiTree T,int key,BiTree f, BiTree *p){
//若结点不存在,则将*p指向父结点
if(T == NULL){
*p = f;
return FALSE;
}
//找到结点,则将*p指向该结点
if(T->data == key){
*p = T;
return TRUE;
}
else if(T->data > key){
return SearchBST(T->lchild, key, T, p);
}
else if(T->data < key){
return SearchBST(T->rchild, key, T, p);
}
return TRUE;
}
三、二叉排序树的插入
算法思路:
1、先查找二叉排序树,若二叉排序树中已经存在该结点,则插入失败;
2、若二叉排序树中不存在对应key值的结点,则比较搜索到的父结点的值;
3、若key值小于父结点的值,则将新结点插入到父结点的左边,作为父结点的左孩子;
4、若key值大于父结点的值,则将新结点插入到父结点的右边,作为父结点的右孩子;
//2.二叉排序树-插入
Status InsertBST(BiTree *T, int key) {
BiTree p;
//查找是否该key值已经存在,若存在,则无需插入
BOOL isExist = SearchBST(*T, key, NULL, &p);
if(isExist){
return FALSE;
}
//当需要插入时,先new一个结点,将结点的值赋值为key。
BiTNode* n = (BiTree)malloc(sizeof(BiTNode));
n->data = key;
n->lchild = NULL;
n->rchild = NULL;
//因为p始终为父结点,当根结点都不存在时,则会出现p为null
if(p == NULL){
*T = n;
}
else if(key < p->data){//当key小于p的值时,则key对应的结点为左孩子
p->lchild = n;
}
else if(key > p->data){//当key大于p的值时,则key对应的结点为右孩子
p->rchild = n;
}
return TRUE;
}
三、二叉排序树的删除
算法思路:
删除共有3种情况:
- 叶子结点;
解决方案:直接删除。 - 只有左孩子或只有右孩子的结点;
解决方案:直接删除结点,重边它的左子树或右子树。 - 既有左孩子又有右孩子的结点;
解决方案:
- 找到欲删除结点p的直接前驱(可通过中序遍历得到)s结点。
- 用s结点来替换p结点。
-
然后再删除p结点。
image.png
//3.从二叉排序树中删除结点p,并重接它的左或者右子树;
Status Delete(BiTree *p){
if(*p == NULL) return FALSE;
BiTree q,s;
/*
删除结点总共3种情况
1、叶子结点
2、只有左孩子或者只有右孩子
3、既有左孩子又有右孩子
算法思路:
叶子结点,直接删除;
当只有左孩子时,只需将左孩子接到当前结点的位置即可;
当只有右孩子时,只需将右孩子接到当前结点的位置即可;
*/
if((*p)->rchild == NULL){//若右子树为空,则将该结点删除后,直接将左孩子替换当前结点
q = *p;
*p = (*p)->lchild;
free(q);
}
else if((*p)->lchild == NULL){
q = *p;
*p = (*p)->rchild;
free(q);
}
else{
q = *p;
s = (*p)->lchild;
while(s->rchild){//找到欲删除结点的直接前驱
q = s;
s = s->rchild;
}
(*p)->data = s->data;//找到替换点,将欲删除结点的值替换成替换点的值
if(q!=*p){
q->rchild = s->lchild;//重接q的右子树
}
else{
q->lchild = s->rchild;//重接q的左子树
}
free(s);
}
return TRUE;
}
//4.查找结点,并将其在二叉排序中删除;
/* 若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点, */
/* 并返回TRUE;否则返回FALSE。 */
Status DeleteBST(BiTree *T,int key){
if(*T == NULL) return FALSE;
BiTree p;
BOOL isExist = SearchBST(*T, key, NULL, &p);
if(!isExist) return FALSE;
//若key为当前结点,则将当前结点删除
if((*T)->data == key){
Delete(T);
}
else if((*T)->data>key){//若key小于当前结点,则左孩子递归找到需要删除的结点
DeleteBST(&(*T)->lchild, key);
}
else{//若key大于当前结点,则右孩子递归找到需要删除的结点
DeleteBST(&(*T)->rchild, key);
}
return TRUE;
}
四、二叉排序树总结
二叉排序树是以链接的方式存储,保持了链接存储结构在执行插入和删除操作时不用移动数据元素的优点,只要找到适合插入和删除的位置后,仅需修改链接指针即可。插入删除的时间性能比较好。
网友评论