二叉树中前驱节点与后继节点的查找

前驱节点

基本概念

一个节点的前驱节点,也就是中序遍历中该节点的前一个节点。举个例子:
在这里插入图片描述
这棵树的中序遍历顺序为:1,2,4,5,7,8,9,11(因为是二叉搜索树,所以中序遍历的顺序是递增)。
那么节点7的前驱是5,节点8的前驱是7。

查找思路

那么该如何查找一个节点的前驱呢,可以确定的是,中序遍历是先访问左子树中的所有节点,再访问根节点,那么由访问次序可知,前驱节点是左子树中最后一个被访问的节点,当然,前提是有左子树。那么又该如何找到左子树中最后访问的节点?显而易见,由中序遍历的次序是左中右可知,最后访问的节点一定是最右端的节点,也就是只需要一直往右走直到没有右节点即可。
比如,下面这棵树的中序遍历最后一个节点一定是30。
在这里插入图片描述

private Node<E> predecessor(Node<E> node){
	Node<E> pre=node.left;
	if(null!=pre){
		while(null!=pre.right)
			pre=pre.right;
		return pre;
	}
}

而当一个节点没有左子树,此时他的前驱节点就可能是父节点(祖父节点…)。如下图中的18节点。
在这里插入图片描述
此时18的前驱节点是10,因为18没有左节点,且18是10右子树中最左侧的节点,访问完10后,下一个访问的就是10右子树,而右子树又要先访问左节点,如此循环,之后访问的就是最左侧节点18。所以前驱节点的寻找方法是,不断地找父节点,直到当前节点是父节点的右节点。

private Node<E> predecessor(Node<E> node){//节点不提供外部的访问
        if(node==null)return null;
        //如果有左节点,则前驱是左子树中最右端的节点
        Node<E> prev=node.left;
        if(prev!=null){
            while(prev.right!=null){
                prev=prev.right;
            }
            return prev;
        }
        //此时没有左节点,则通过父节点寻找,且该节点必须是父节点右节点
        //如果该节点是父节点的左节点则向上迭代
        while(node.parent!=null&&node.parent.left==node){
            node=node.parent;
        }
        //node.parent==null
        //node.parent.right==node
        //不管是那种情况,return即可
        return node.parent;
    }

后继节点

后继节点显然是中序遍历中当前节点的下一个节点。
查找思路也一模一样,只不过方向正好相反。在有右子树的情况下,后驱节点一定是右子树最左侧的节点。在没有右子树的情况下,后驱节点是其父节点(祖父…),通过不断迭代查找,且必须满足当前迭代到的节点是其父节点的左节点,比如下图中的7节点,其后继节点就是祖祖父节点10,且此时7在10的左子树中,也就是5是10的左节点。
在这里插入图片描述

/**
     * 获取该节点的后继节点,即中序遍历的后节点
     * @param node
     * @return
     */
    private Node<E> successor(Node<E> node){
        Node<E> prev=node.right;
        //当右节点不为空,寻找右子树中最左端的节点
        if(null!=prev){
            while(prev.left!=null){
                prev=prev.left;
            }
            return prev;
        }
        //此时右节点为空,后继节点为父节点(祖父..),且父节点的左节点是当前节点
        //去掉中间的作为父节点右节点的节点
        while(null!=node.parent&&node==node.parent.right){
            node=node.parent;
        }
        //null==node
        //node==node.parent.right
        return node.parent;
    }
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值