基于JDK TreeMap分析树的后继结点查询算法

个人博客: 基于JDK TreeMap分析树的后继结点查询算法 | iwts's blog

核心在于TreeMap的successor()方法

只要理解二叉搜索树,就能看懂这个方法了。注释为:

Returns the successor of the specified Entry, or null if no such.

就是说返回当前结点的后继结点。然而TreeMap底层是红黑树谈何后继结点?这个方法最早出现是在containsValue方法中。 也就是传入一个Value,判定是否存在。也就是说我们需要遍历整个红黑树。但是这样的遍历用递归肯定是不行的,性能太差,而BFS又需要实现queue,不显示,所以就有了successor方法,能够快速获取结点的后继结点。这里我们先看图。因为虽然TreeMap的底层是红黑树,但是在不涉及平衡的前提下,其他操作其实跟二叉搜索树一样,所以图都按照二叉搜索树来画:

我们认为,将BST“压平”,就是一个有序数组。而所谓的后继结点,就是指在“数组状态”下,按顺序遍历的情况,可以理解为迭代。严格地说,有点类似严格ceil方法:寻找大于该结点的所有结点中,值最小的结点。

        可以看到,不管怎样,对于一个结点而言,下一个节点一定是在树的右边,区别在于:比当前树更高还是更低:

1.比当前结点更低:就是该结点有右子树的情况,那么这个值很好确定:右子树的最小值。可以看下图,如果查找1的下一个结点,就是找右子树的最小值:

2.比当前结点更高:就是该结点没有右子树但是有比该结点大的祖先结点。可以看下面的图,这个也是非常核心的算法:

3.当前结点就是最大值,这就需要返回null了。最大值的时候只有这两种可能:

这样来说,我们可以先看1的情况如何实现:

if (t.right != null) {
    Entry<K,V> p = t.right;
    while (p.left != null)
        p = p.left;
    return p;
}

因为2、3都是建立在不存在右子树的情况,所以存在右子树,一定就是找右子树的最小值。

核心就是2、3——如何判定到底该结点是不是最大值?我们假设从该节点回溯到根节点是“上山的过程”,那么满足条件2的情况实际上就是在一直遍历父结点的时候“往右拐了”一下。看2的图和3的图:如果父结点一直都是通过右子树,直到遍历到根,那么说明该节点就是最大值,而如果其中一个父结点,是左子树进入到该节点的,那么这个父结点就是我们要找的值。算法非常简单明了:

Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
while (p != null && ch == p.right) {
    ch = p;
    p = p.parent;
}
return p;

这个while的过程就是不断向上回溯的过程。在保证p不为null的时候,一直在判定ch是否是p的右子结点。如果是,则继续向上找,如果不是,说明该结点就是第一个大于值的结点。如果直到p == null都没有找到,那么就说明该结点是整个树的最大值。

        源码也很简单:

static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } else {
        Entry<K,V> p = t.parent;
        Entry<K,V> ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Github上创建一个基于JDK 17的项目可以按照以下步骤进行操作: 1. 首先,在Github上创建一个新的项目仓库。 2. 在项目仓库中,点击"Actions"选项卡,然后点击"New workflow"按钮创建一个新的工作流程。 3. 在工作流程文件中,可以使用官方提供的示例代码来设置基本的工作流程。示例代码中会指定使用JDK 17来构建项目。 4. 在工作流程文件中,可以使用actions/setup-java插件来设置JDK 17的环境。在插件的配置中,可以指定使用Temurin作为开源JDK的类型,并设置Java版本为17。 5. 在工作流程文件中,可以使用其他适合的插件或命令来构建和测试项目。例如,可以使用Maven来构建Java项目。 6. 完成工作流程文件的配置后,保存并提交文件到项目仓库的.github/workflows目录下。 7. 提交工作流程文件后,Github会自动运行工作流程,并根据配置的触发条件执行相应的操作。 通过以上步骤,你就可以在Github上创建一个基于JDK 17的项目,并使用工作流程来构建和测试项目了。 #### 引用[.reference_title] - *1* *3* [github action 基于个人项目实践](https://blog.csdn.net/xiaoliizi/article/details/131145170)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [github上的java项目怎么运行(面向小白)](https://blog.csdn.net/weixin_39654436/article/details/111460159)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值