如何知道哪个函数的复杂度为 log n

How to know which function has complexity of log n

我正在学习时间复杂度并且被困在大 O(log n) bcoz 我无法确定哪个函数具有 log n 的复杂性与其他复杂性如 O(n)、O( n2) 或 O(n3) 可以通过计算函数中的 for 循环次数轻松识别

您想看两件事:

  • 循环迭代了多少次? (深度)
  • 它在每次迭代中访问了多少数组? (宽度)

对于深度:

  • 如果每次迭代将剩余迭代次数除以某个数量(通常为2),则可能有log(n)次迭代,因此深度为O(log(n )).它除以的确切值对于大 O 无关紧要,因为 log_2(n)、log_e(n)、log_10(n) 等都是每个值的常数倍数其他.
  • 如果迭代固定次数,那就是O(1)。
  • 如果它迭代 n 次(或它的常数倍),它是 O(n)

对于广度,请问每次迭代需要查看原始数组的多少个元素。

  • 如果该数字根本不依赖于大小,则宽度为 O(1)(例如,在二进制搜索中,我们每次迭代只查看一个元素,而不管数组大小)。
  • 如果你查看整个数组,或者它的某个常数部分,例如n/2,宽度为O(n)。良好的排序算法通常就是这种情况。 (这些通常通过递归而不是循环工作,这意味着深度是递归的深度而不是迭代次数。对于这些,你问有多少数组被访问集体所有递归在同一层调用 。如果你还没有学过递归,请暂时忽略这个括号。)

一旦你有了广度和深度的大 O 估计,只需将它们相乘即可。

  • 排序数组的二分查找深度为log(n),宽度为O(1),所以是O(log(n))
  • 合并排序的深度为 O(log(n)),宽度为 O(n),所以它是 O(n log(n))
  • 将数组中的所有数字相加的深度为 O(n),宽度为 O(1),因此为 O(n)。
  • 两个数相加的深度为 O(1),宽度为 O(1),因此为 O(1)。

当然,在实践中会出现一些复杂情况(通常是递归情况),但这些启发式方法可以帮助您入门。一种可能对更复杂的情况有用的技术是勾勒出每个 iteration/recursive 调用访问的元素。纵向有深度,横向有广度。只要您没有多个函数调用访问同一行中的同一内存,您通常可以清楚地看到发生了什么,以便将事情加起来。