算法导论---二叉搜索树

本文介绍了二叉搜索树的性质,包括每个节点的左右子节点大小关系,并详细阐述了寻找后继和前趋的伪代码。同时,讨论了插入、删除节点的算法,特别是针对目标节点不同情况的删除策略,包括目标节点为叶子节点、单子节点和双子节点的情况。删除操作中特别提到了一种特殊情况,即目标节点的右孩子是其后继。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉搜索树

有如下性质:
1. 对任意某一结点,其左子树(若存在)的任一结点比该结点小,其右子树(若存在)的任一结点比该节点大。
2. 每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。

其它一些重要结论:
如果二叉查找树中的某个结点有两个子女,则其后继没有左孩子,其前趋没有右孩子。

后继定义:对结点x而言,存在一个结点集合,集合内任一结点的key值都比x的key值大。而结点x的后继,既是该集合内的最小key值的结点。

寻找后继 伪代码:

TREE_SUCCESSOR(x)
    if right(x) != NIL
    //若目标结点x的右子树非空,则对右子树调用TREE_MINIMUM()得出后继
        then return TREE_MINIMUM(right[x])

    y <- p[x] //令y做结点x的父结点

    //若y结点非空,则当发现结点x是父结点y的左孩子时,y即为结点x后继
    while y != NIL and x == right[y]
        do x <- y
        y <- p[y]

    return y

寻找前趋 伪代码

TREE_PREDECESSOR(x)
//寻找前趋的过程与寻找后继过程对称的
    if left(x) != NIL
        then return TREE_MAXIMUM(left[x])

    y <- p[x]

    while y != NIL x == left[x]
        do x <- y
        y <- p[y]

    return y

插入元素
伪代码:

//T参数指该树,z结点是将要插入的结点
TREE_INSERT(T, z)
    //x结点是当前结点,y结点是x结点的父结点
    y<-NIL;
    x<-y;

    //如果x为空,说明了当前结点已经到达最底部
    //并且 这个NIL所占的位置,既是z结点要插入的位置
    while x != NIL
        do y <- x   //将父结点指向当前结点
            if key[z] < key[x]
            //如果目标结点z小于当前结点x
            //则令当前结点x向左结点走
                then x <- left[x]

                //否则,当前结点x向右结点走
                else x <- right[x]

    //使得z结点parent指针指向y结点                
    p[z] <- y

    if y=NIL 
    //若树T是空的,则z结点直接插入到树的根结点
        then root[T] <- z
        //否则,根据结点z与y的key值大小比较,向左或者向右插入z结点
            else if key[z] < key[y]
                then left[y] <- z
                else right[y] <- z

删除结点

仔细想想,目标结点有三种情况
1. 目标结点为叶子结点,则可以直接删除
2. 目标结点只有一个孩子,则可以使目标结点的孩子的parent指针指向目标结点的父结点,使目标结点的父结点指向目标结点的孩子结点,然后删除目标结点
3. 目标结点有两个孩子结点,则使目标结点的后继替换目标结点的位置,而由于上面提到过的结论(如果二叉查找树中的某个结点有两个子女,则其后继没有做子女,其前趋没有右子女。)可知,其后继没有左孩子,则使其后继的右孩子与后继的父结点关联起来即可。然后用后继替代目标结点。

对于第3种情况,有一个比较特殊的情况是,目标结点的右孩子是其后继。

算法导论第三版的删除节点的思路:

  1. 目标节点的左孩子为NIL,则直接由其右孩子代替其本身,无论右孩子是否为NIL,如图a
  2. 目标节点的左孩子非NIL,且右孩子为NIL,则由左孩子代替其本身,如图b
  3. 目标节点的两个孩子非NIL,且后继是其右孩子,则直接有其右孩子代替其本身,如图c
  4. 目标节点的两个孩子非NIL,且后继不是右孩子,则先将后继的右孩子(无论是否NIL)代替后继本身(该后继必定无左孩子),然后用后继替换目标节点,如图d




删除结点 伪代码:

    TREE_DELETE(T, z)
        if z.left == NIL
            TRANSPLANT(T, z, z.right)
        elseif z.right == NIL
            TRANSPLANT(T, z, z.left)
        else y = TREE_MININUM(z.right)
            if y.p != z
                TRANSPLANT(T, y, y.right)
                y.right = z.right
                y.right.p = y
            TRANSPLANT(T, z, y)
            y.left = z.left
            y.left.p = y

而TRANSPLANT函数用于子树的替换

TRANSPLANT(T, u, e)
    if u.p == NIL
        T.root = v
    elseif u.p.left == u
        u.p.left = v
    else
        u.p.right = v
    if v != NIL
        v.p = u.p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值