Autoboxing的Big O复杂性是什么?

时间:2017-10-29 01:03:10

标签: java algorithm big-o

我知道我们总是谈论自动装箱时的性能损失,但我想知道这是否会影响算法的Big O复杂性。

Character类的构造函数的Java实现是:

public Character(char value) {
    this.value = value;
}

构造函数是常量时间,因此它实际上归结为对象创建。对象创建会影响Big O时间吗?例如,如果你将String的字符放入HashSet<Character>仍然是O(n),其中n是字符串中的字符数?

1 个答案:

答案 0 :(得分:2)

简短的回答是否定的。它不会改变复杂性。

在所有情况下,自动装箱单个值的复杂性为O(1)。平均而言,将单个元素添加到HashSet的成本是O(1)摊销的。一次完成这两件事的成本仍然是平均O(1)

将元素添加到HashSet的实际成本变化很大。可变性归因于两件事:

  • 由于哈希函数选择不当或“运气不好”导致的哈希冲突,可能导致HashSet搜索长哈希链。在最坏的情况下,可以是O(N)。举个例子,这些东西不适用 1

  • 如果HashSet中的元素数量不断增加,它将定期重新分配其哈希数组并重新创建哈希链。但是,由于HashSet算法每次都会使数组大小加倍,因此摊销的开销不会改变每次插入的O(1)平均成本。

自动装箱的实际成本也是可变的。对于某些原语,相应的Wrapper类型为原始值范围的子集维护先前实例化的自动装箱值的高速缓存。如果valueOf(prim)给出缓存命中,则不会分配新对象。

对于您的示例,Character缓存U0000到U007F的盒装值。

有人提到内存分配的成本不一定是O(1)。这在技术上是正确的。但是,为了达到比O(1)更糟糕的行为,你需要做一些不好的事情; e.g。

  • 堆太接近满,导致GC人体工程学不良。
  • 使用过多可用物理内存并导致虚拟机抖动的堆。
  • (在多核系统上)太多线程试图同时访问堆的太多不同区域,导致h / w级内存缓存争用和管道停滞。

解决这些问题的方法往往是增加堆大小,购买更多内存,获得更强大的机器......或重新设计算法。

1 - 最差情况行为O(N)仅在散列函数不良和/或不幸的元素模式时发生。对于原始包装器,前者不可能发生:例如,查看Character::hashCode()的实现。后者不可能发生,因为Character实现Comparable