今天,我遇到了一个与Java HashMaps有关的面试问题,我想澄清一些关于Java 8和更高版本中某些操作的时间复杂性和关键比较的问题.

给出下面的代码片段,考虑到Java 8对HashMap的改进,这map.get(new Key(1));行的时间复杂度是多少?

import java.util.*;

class Key {
    int v;

    public Key(int v) {
        this.v = v;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Key key = (Key) o;
        return v == key.v;
    }

    @Override
    public int hashCode() {
        return 0; // always hash collision
    }
}

class Solution {
    public static void main(String[] args) {
        int n = 1_000_000;
        Map<Key, Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            Key key = new Key(i);
            map.put(key, i);
        }
        map.get(new Key(1)); // What's the time complexity of this line?
    }
}

我最初的回答是O(log n),提到Java 8自动将bucket中的冗长链表转换为红黑树,以提高效率.

Q1:然而,面试官随后询问了how comparison is done within the RB Tree when the Key class doesn't implement the 100 interface.

我回答说,hashCode首先用于比较,因为即使在同一个桶中,它也只意味着h1 % length == h2 % length.在进一步询问哈希代码相同的情况下,我提到了System.identityHashCode的用法.我的答案和https://stackoverflow.com/a/43911638/10969942一样

Q2:这引发了关于the case where two keys are 100 but likely have different 101 values:的讨论

Key k1 = new Key(1); 
Key k2 = new Key(1);

我推测这可能需要遍历子树中的所有条目,使用相同的哈希代码.Then the interviewer asked whether it means that the worst case time complexity is O(n)? I don't know since I always heard that after Java8, HashMap can have guaranteed worst case O(log n) time complexity.

Q3:然后,采访者询问如何将两个具有相同System.identityHashCode的不同密钥插入到映射中,假定RB树不允许重复密钥:

Key k1 = new Key(1); // same identityHashCode
Key k2 = new Key(2); // same identityHashCode

我记得不同的对象有可能有相同的System.identityHashCode https://stackoverflow.com/a/1063100/10969942,但我不清楚HashMap如何管理这些插入而不违反RB树的约束,即处理hashCode和identityHashCode冲突.

推荐答案

给出下面的代码片段,考虑到Java 8对HashMap的改进,map. get(new Key(1));行的时间复杂度是多少?

是O(n).

我最初的回答是O(log n),提到Java 8自动 将桶中的冗长链表转换为红黑树, 效率

是的 在这种情况下,每个键都有相同的哈希代码,所以只有一个哈希桶. 有了足够的条目,它将被组织为一个平衡的树.

Q1:然而,面试官随后询问了how comparison is done within the RB Tree when the Key class doesn't implement the 100 interface.

正如你所说的,当散列代码相等且密钥类型没有自然顺序时,树顺序会回到标识散列代码.

Q2:这就引出了关于the case where two keys are 100 but likely have different 101 values的讨论:

这对HashMap人来说是个问题. 如果要查找的关键字与 map 中已经存在的对象相同,那么它将在O(log n)步中找到,但如果不是,则仍然需要在 map 中搜索一个equals()到它.如果存在这样的关键字,则需要花费O(n)步,如果没有,则需要花费θ(n)步.

Then the interviewer asked whether it means that the worst case time complexity is O(n)?

是的

I don't know since I always heard that after Java8, HashMap can have guaranteed worst case O(log n) time complexity.

希望你没说that. 一个好的面试官不会指望你什么都知道,人们可以通过各种各样的方式获得错误信息.但在 bootstrap 你得出结论后,他们有理由期望你接受它,至少承认这个结论似乎是合理的.

Q3:问:两个不同的 keys 是怎么回事? 同样的System.identityHashCode可以插入到 map 中, RB树不允许重复密钥:

我想这里的假设是

不同的对象可能有相同的System. identityHashCode

诚然,Java并不保证不同的身份哈希代码,但它does specify:

在合理可行的情况下,类Object定义的hashCode方法为不同的对象返回不同的整数.

(ObjecthashCode()实现当然是身份散列码.

我不清楚HashMap如何管理这些插入而不违反RB树的约束,即处理hashCode和identityHashCode冲突.

我不知道我的头,快速判断doctor 没有找到答案.但假设HashMap does处理这种情况,我希望它在每个树 node 中都有一个链表,或类似的. 这并不存在与在bucket级别使用链表相同的问题,因为可以依赖标准库实现来提供相当好的身份散列代码(见上文).

即使这不是HashMap实际上做的,我怀疑面试官会对它感到满意.同样,他们并不期望你做到know每件事,但他们很可能在寻找那些准备好think的人.

Java相关问答推荐

如何让HikariCP指标在NewRelic中正确显示?

Selenium Java:无法访问IFRAME内部的元素

Mat. n_Delete()和Mat. n_release的区别

Java Stream,需要更新列表对象列表

SQlite for Android无法使用json_group_array/json_object

neo4j java驱动程序是否会在错误发生时自动回滚事务?

对运行在GraalVM-21上的JavaFX应用程序使用分代ZGC会警告不支持JVMCI,为什么?

JavaFX Maven Assembly插件一直打包到错误的JDK版本

Java中如何根据Font.canDisplay方法对字符串进行分段

OpenGL ES 3.0-纹理黑色

如何在Spring Java中从数据库列中获取JSON中的具体数据

我如何解释这个错误?必需类型:供应商R,提供:收集器对象,捕获?,java.util.List java.lang.Object>>

使用Jolt将字段转换为列表

使SLF4J在Android中登录到Logcat,在测试中登录到控制台(Gradle依赖问题)

如何从日期中截取时间并将其传递给组件?

A.ForEach与For(类型a:集合)

深度优先搜索实现:算法只向右搜索

在Java Spring JPA中插入包含对其他实体的引用的列

基于距离的APACHE POI公式判断

Java 21保护模式的穷尽性