查找-树表的查找-二叉排序树

二叉排序树的定义

二叉排序树(Binary Sort Tree)又称二叉查找树,它是一种对排序和查找都有用的特殊二叉树。
定义:
二叉排序树或者是空二叉树,或者是具有下列特性的二叉树:

  • 左子树上所有结点的关键字均小于根结点的关键字;
  • 右子树上所有结点的关键字均大于根结点的关键字;
  • 左子树和右子树又各是一课二叉树。
//二叉排序树结点
typedef int KeyType;
typedef struct {
    
    
    KeyType key;
    char info[];
}ElemType;

typedef struct BSTNode{
    
    
    ElemType data;
    struct BSTNode * lchild;
    struct BSTNode * rchild;
}BSTNode,*BSTree;

在这里插入图片描述

左子树结点值 < 根节点值 < 右子树结点值
⇓ \quad\qquad\qquad\qquad \Downarrow
进行中序遍历,可以得到一个递增的有序序列

查找操作

因为二叉排序树可以看成一个有序表,所以在二叉排序树上进行查找和折半查找类似,也是一个逐步缩小查找范围的过程。

算法描述:

① 若二叉排序树为空,则查找失败,返回空指针。
② 若二叉排序树非空,将给定的key与根结点的关键字进行比较;

  • 若相等,则查找成功,返回根结点指针;
  • 若小于根结点,则在左子树上递归查找
  • 若大于根结点,则在右子树上递归查找。
    算法描述:
BSTree SearchBST(BSTree T,KeyType key){
    
    
    if((!T)||key==T->data.key)
        return T;
    else if(key<T->data.key)
        return SearchBST(T->lchild,key);
    else
        return SearchBST(T->rchild,key);
}

插入操作

二叉排序树的插入操作是以查找为基础的。要将一个关键字值为key的结点 * S 插入到二叉排序树中,则需要从根结点向下查找,当树中部存在关键字等于key的结点时才进行插入。新插入结点一定是一个新添加的叶子结点,并且是查找部成功时查找路径上访问的最后一个结点的左孩子或者右孩子结点。

算法描述

① 若二叉排序树为空,则待插入结点 *S 作为根结点插入到空树中。
② 若二叉排序树非空,将给定的key与根结点的关键字(T->data.key)进行比较:

扫描二维码关注公众号,回复: 16679223 查看本文章
  • 若key< T->data.key,则将*S 插入左子树;
  • 若key>T->data.key,则将*S插入右子树。
int InsertBST(BSTree &T, ElemType e) {
    
    
    if (!T) {
    
    
        T = (BSTree) malloc(sizeof(BSTNode));
        T->data = e;
        T->lchild = T->rchild = NULL;
        return 1;
    } else if (e.key == T->data.key)
        return 0;
    else if (e.key < T->data.key)
        return InsertBST(T->lchild, e);
    else if (e.key > T->data.key)
        return InsertBST(T->rchild, e);
}

删除操作

被删除的结点可能是二叉排序树的任何结点,删除结点后,要根据其位置不同修改其双亲结点及其相关结点的指针,以保持二叉排序树的特性。
在这里插入图片描述

若被删除的结点z时叶子结点,则直接删除,不会颇为二叉排序树的特性。
在这里插入图片描述

若结点z只有左子树,则让z的子树成为z父结点的子树,替代z的位置。
在这里插入图片描述
若结点z只有右子树,则让z的子树成为z父结点的子树,替代z的位置。
在这里插入图片描述
若结点z左、右子树不为空,则令z的直接前驱替代z,然后从二叉排序树中删除去这个直接前驱,这样就转换成了①或②情况。
在这里插入图片描述
若结点z左、右子树不为空,则令z的直接后继替代z,然后从二叉排序树中删除去这个直接后继,这样就转换成了①或②情况。

算法描述:

  1. 首先查找关键字为key的待删除结点:
    ① 若被删除的结点z时叶子结点,则直接删除,不会颇为二叉排序树的特性。
    ② 若结点z只有左子树或只有右子树,则让z的子树成为z父结点的子树,替代z的位置。
    ③ 若结点z左、右子树不为空,则令z的直接后继(或直接前驱)替代z,然后从二叉排序树中删除去这个直接后继(或直接前驱),这样就转换成了①或②情况。
void DeleteBST(BSTree &T, KeyType key) {
    
    
    BSTNode *z = T; //待删除的结点
    BSTNode *f = NULL; //待删除结点 *z 的双亲结点
    /**----------------------- while循环从根开始查找关键字等于key的结点*z -----------------------*/
    while (z) {
    
    
        if (z->data.key == key)
            break; //找到关键字等于key的结点 *z
        f = z; //*f 为 *p的双亲结点
        if (z->data.key > key)
            z = z->lchild; //在*z 的左子树中继续查找
        else
            z = z->rchild;    //在 *p的右子树中继续查找
    }

    if (!z)return; //找不到待删除的结点;
    /**------------ 考虑3中情况实现p所指子树内部的处理:*p左右子树不为空、无左子树、无右子树 ------------*/
    BSTNode *q = z;
    if (z->lchild && z->rchild) {
    
     //待删除结点*z 左右子树均不为空
        BSTNode *s = z->lchild;
        while (s->rchild) {
    
     //在*p的左子树中继续查找其前驱结点,即最右下结点
            q = s;
            s = s->rchild; //向右到尽头
        }
        z->data = s->data; //s指向待删除结点的前驱
        if (q != z)
            q->rchild = s->lchild; //重接*q的右子树
        else
            q->lchild = s->lchild; //重接*q的左子树
        delete s;
        return;
    } else if (!z->rchild) {
    
    //待删除结点*p无右子树结点,只需重接其左子树
        z = z->lchild;
    } else if (!z->lchild) {
    
    //待删除结点*z 无左子树结点,只需重接其右子树
        z = z->rchild;
    }
    /**------------------------- 将p所指的子树挂接到其双亲结点*f相应的位置 -------------------------*/
    if (!f)  //被删除结点为根结点
        T = z;
    else if (q == f->lchild)
        f->lchild = z; //挂接到*f的左子树位置
    else
        f->rchild = z; //挂接到*f的右子树位置
    delete q;

}

创建操作

二叉排序树的创建操作时从空二叉排序树开始的,没输入一个结点,经过查找 操作,将新结点插入到当前二叉排序树的适当位置。

算法描述:

① 将二叉排序树T初始化为空树。
② 读入一个关键字为key的结点。
③ 如果读入的关键字key不是输入结束标志,则循环执行以下操作:

  • 将此几点插入二叉排序树T中;
  • 读入一个关键字为key的结点。
void CreatBST(BSTree &T) {
    
    
    T = NULL;
    ElemType e;
    cin >> e;
    while (e.key != '\0') {
    
    
        InsertBST(T, e);
        cin >> e;
    }
}

查找效率分析

猜你喜欢

转载自blog.csdn.net/QQ657205470/article/details/127427327