【问题标题】:How to determine the worst case complexity of methods in HashMap?如何确定HashMap中方法的最坏情况复杂度?
【发布时间】:2013-12-03 20:47:10
【问题描述】:
public void addOccurence(String word) { 
    if (hm.containsKey(word)){
          hm.put(word, hm.get(word)+1);
    }
    else {hm.put(word, 1); }
}

我知道平均put(k,v)get(v) 采取o(1),他们最坏的情况是o(n)containsKey(v) 呢? 以及如何确定诸如此类的东西的运行时间:

hm.put(word, hm.get(word)+1) 

最坏情况下是o(n^2),平均情况下是o(1)吗?

【问题讨论】:

  • O(2*n) = O(n)。常数乘数对大 O 渐近线没有影响。 (另外,您不是说第一段中的“最坏情况”,而不是“单词情况”吗?)
  • 选中此项以了解 java8+ stackoverflow.com/questions/8923251/…

标签: java hashmap runtime time-complexity


【解决方案1】:

hm.put(word, hm.get(word)+1) 的最坏情况时间复杂度是O(N)

如何:假设你由于过度碰撞你的hashMap变成了一个链表。所以get() 将不得不搜索整个链表,因此O(N)。同样hm.put() 需要遍历链表来插入值。所以O(N)+O(N) = O(2N) ~ = O(N)

即使对于插入,您不会遍历整个链表,那么 get() 方法的时间复杂度也是 O(N)。所以总数是O(N)。所以在这两种情况下,最坏情况的时间复杂度都是O(N)

这在 Java-8 中有所不同,因为如果桶变得大于 TREEIFY_THRESHOLD,它会将链接列表转换为树。

但它的渐近下界是O(1)

如何: 因为如果您的密钥分布良好,那么get() 将具有o(1) 的时间复杂度,insert 的时间复杂度也相同。所以导致O(1) 的时间复杂度是渐近的。

【讨论】:

【解决方案2】:

最坏的情况是 O(N)。 你正在做两个或三个操作,每个操作最坏的情况是 O(N), 所以你有 3N 仍然是 O(N)。 你没有做任何二次性质的事情。

【讨论】:

    【解决方案3】:

    O(N) 并不是最坏的情况。 HashMap 仅声称具有恒定的工作时间。事实上它不是真的。当超过特殊阈值时,通常通过重新散列 Map 来保持恒定的工作时间。看看内部 HashMap 方法:

    void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
    
        createEntry(hash, key, value, bucketIndex);
    }
    

    如果大小大于阈值,则发生完全重新散列,其复杂性等于创建新的 HashMap。所以最坏的情况是

    O(new HashMap(oldMap)) + O(N)

    O(N) 如果您严重覆盖了 hashCode() 函数,则可能会发生,因此它具有纯分布。对于默认实现,这不会发生。唯一的危险在于重新散列。

    【讨论】:

      【解决方案4】:

      最坏的情况下运行时不是O(n^2),因为您没有嵌套循环,每个循环都有O(n) RT。运行时间为 O(n),因为您正在将来自 hm.put(word, hm.get(word)+1) 方法的 RT 添加到来自 hm.containsKey(word) 方法的 RT。还有O(n) + O(n) = O(2n) ==> O(n)

      最好的情况当然是字符串不在 hashmap 中并且执行了else(...) 语句,或者O(1)

      public void addOccurence(String word) { 
          if (hm.containsKey(word)){ //Worst Case O(n)
              hm.put(word, hm.get(word)+1); //Worst case O(n)
          }
          else {hm.put(word, 1); }  //O(1) Runtime
      }
      

      附带说明,containsKey(k) 方法基本上是一个 get(k) 方法,它根据密钥是否存在返回布尔值。另一方面,get(k) 方法实际上会返回键的值,假设键存在于哈希图中。两者的运行时是相同的,因为它们基本上以相同的方式搜索哈希图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多