【问题标题】:What is the time complexity to access/find HashMap bucket(Not value in bucket)?访问/查找 HashMap 存储桶的时间复杂度是多少(不是存储桶中的值)?
【发布时间】:2018-11-28 17:02:08
【问题描述】:

假设我们有两个不同的 hashMap,比如 map1 和 map2。

  • map1 有 1000 个条目和 1000 个桶。
  • map2 有 999999 个条目和 999999 个桶。

假设我们有一个哈希码为“1234”的对象“obj1”,我们将该对象作为 map1 和 map2 中的键(值为“xyz”)。

在 map2 中查找“obj1”值是否需要更多时间? 从 map1 和 map2 访问 obj1 的时间复杂度仍然是 O(1) 吗?

【问题讨论】:

  • 为什么你认为它会有所不同?在给定哈希码的情况下查找哈希桶是模运算和数组访问。如果您使用更大的数字,这些成本都不会更高。显然有更多的因素影响它,比如有多少哈希码冲突(地图中的所有对象都具有相同的哈希码吗?)
  • @Krease - 在 HashMap 中,它创建数组来保存哈希码,我们称它们为 Arrayof HashCodes/Buckets。所以如果我想从那个Array中找到hashcode,我还需要遍历它对吗?
  • 您不会“遍历”存储桶数组,而是使用存储桶数量对哈希进行模运算 - 他为您提供了对象所在的存储桶。如果您有 collisions(桶中的多个对象),然后遍历它。不过,您的问题并未说明任何有关碰撞的内容
  • 是的。我明白了。你的意思是说“hashcode % sizeOfmap”对吗?
  • 是的。 % 字符是 Java 中的模运算。

标签: java data-structures hashmap


【解决方案1】:

HashMap 中查找存储桶的时间为 O(1),始终与容量(存储桶数量)无关。

假设您的obj1 的哈希码为1234567HashMap 的核心不是搜索正确的桶(就像 TreeMap 所做的那样),而是计算它的位置,并立即访问具有该编号的桶。这就是哈希码进入游戏的地方。

计算是obj.hashCode() % capacity,结果数字给出了bucketsArray的索引。

  • 对于小哈希图,为1234567 % 1000 = 567,表示相关桶为bucketsArray[567]

  • 对于大的,它是1234567 % 999999 = 234568,导致bucketsArray[234568]

计算除数所需的时间是恒定的,与值无关。访问具有给定索引的数组的时间也是恒定的,因此是 O(1)。

我们只讨论了找到存储桶。如果存储桶包含多个条目,则线性搜索会完成哈希映射访问,这是 O(K),其中 K 是(平均?最大?)存储桶中的条目数。

【讨论】:

    【解决方案2】:

    我认为最好用代码和图表来回答。我们都知道散列(一种方式)函数是什么。基本上它接受任意输入并返回数字(在 java 中它是 int 但并非总是如此)。 java中的int有32位。这意味着它可以在 -2,147,483,648 和 2,147,483,647 之间。存在的每个 java heep 上的每个对象都可以计算它的哈希值(使用 java.util.Object 类中的方法),并且它必须在那个区间内。

    现在假设我们有 3 个对象。

    21234 = obj1.hashCode();  
    623424 = obj2.hashCode();
    23124432 = obj3.hasCode();
    

    我们想将它们添加到一个有 200 个桶的 hashMap 中。 (这不是我在这里输入的有效 Java 代码)

    public class MyHashMap {
        private final Buckets[] buckets = new Buckets[200];
    
        public boolean add(Object object){
            int resultModulo = object.hashCode() % 200;
            buckets[buckets].add(object);
        } 
    }
    

    现在为了最后的和平。对于我们的对象,resultModulo 将是 34(21234)、24(623424)、32(23124432)。并且计算数量不会超过200。

    数组被分配为一块连续的内存。只是指针数组(64 位)而不是实际对象。所以 bucktes[] 看起来是这样的

    0xB80000xB80020xB80670xC1101 ....
    1      2      3      4       .... 200
    

    所以当您的代码调用 bucket[34],bucket[24],bucket[32] 时,硬件的作用是:

      mov eax, bucktes[ecx*19] 
      ; eax now contains the pointer to the
      ; 19 element in the array
      ; this is a one clock instruction
    

    这就是为什么你有多少桶并不重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 2014-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多