反复引用会增加时间复杂度吗?

时间:2018-04-15 22:54:02

标签: java time-complexity

假设我有一个if语句,如下所示

Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
    map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
    int complement = target - nums[i];
    if (map.containsKey(complement) && map.get(complement) != i) {
        return new int[] { i, map.get(complement) };
    }
}

如果if语句的计算结果为true,那么map.get(complement)会被程序运行两次,使得在此if语句之前使用变量更有利于分配此取消引用的结果,或者编译器/堆是否更有利(或其他东西)将此值保留在内存中,以便这样的多个语句只被评估一次?如果它被评估两次,那么这会增加像哈希映射这样的东西的时间复杂度,或者查找只需要O(1)时间,所以它真的不重要吗?

3 个答案:

答案 0 :(得分:3)

class Example(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): ... self.show() newAct3.triggered.connect(self.on_triggered) @QtCore.pyqtSlot() def on_triggered(self): w = QDialog(self) w.resize(640, 480) w.exec_() ... 的查询需要HashMap 对于时间复杂度,常数因素不重要,因此,如果您执行两次O(1)调用,则自O(1)以来仍然只有O(1)。像

这样的东西
O(2) = O(1)

仍然在map.get(complement) map.get(complement) map.get(complement) map.get(complement) ,因为你只执行它一定次数,与输入变量无关。

Java本身并未优化 O(1)调用,地图可能在两次调用之间发生了变化。至少我不知道一个编译器,但也许有一些深入分析你的代码。

循环本身位于map.get(complement) O(n),因为您至少有最糟糕的情况(地图不包含密钥),您完全迭代它,产生n = nums.length O(n)。可能也是典型的情况,因为你的n = nums.length可能在任何地方,可能没有模式可以使它只产生不断的迭代。

上面的循环也在complement中运行,因为它执行O(n)个语句O(1) - 次。

答案 1 :(得分:1)

由于编译器/ JIT无法知道对方法的两次调用是否会产生相同的结果,因此无法优化调用。鉴于任何程序可能是多线程的,甚至可能是这样,如果没有适当的同步,则在两次调用之间修改映射,get的结果返回不同的对象。

如果您要求的密钥不存在,get方法将返回null,代码可以重写为:

for (int i = 0; i < nums.length; i++) {
   int complement = target - nums[i];
   Integer value = map.get(complement);

   if (value != null && value != i) {
       return new int[] { i, value };
   }
}

答案 2 :(得分:0)

不,时间复杂度不会改变:通过if - 语句的每个可能执行路径所需的时间可以超过查找所需的时间,乘以因子3,加上一些开销用于所有其他恒定时间计算。对于正常数,O(3 * constant_1 + constant_2)渐近渐近O(1)

由于不保证引用透明性,编译器不会优化三个查找。

然而,理论上(可能在将来的版本中)哈希映射的具体实现可以维护具有预先计算的哈希码的缓存以及它们在内部存储的数组中对于最近已传递给{{的键的位置。 1}}方法。

要考虑的另一个因素是硬件如何处理内存访问。可以通过一个足够聪明的内存管理器,在第二次访问时,哈希映射的内容是“温暖的”,这样第二次和第三次访问就没那么重要了。

结论:不,渐近运行时不会改变。首先纠正它。然后对其进行分析然后在必要时对其进行优化。