【问题标题】:How to know when Big O is Logarithmic?如何知道大 O 何时是对数?
【发布时间】:2010-10-19 11:41:25
【问题描述】:

我的问题来自"Plain English Explanation of Big O" 的帖子。我不知道对数复杂度的确切含义。我知道我可以在时间和操作次数之间进行回归并计算 X 平方值,从而确定复杂度。但是,我想知道一种在纸上快速确定它的方法。

如何确定对数复杂度?有什么好的基准吗?

【问题讨论】:

    标签: algorithm math big-o recurrence logarithm


    【解决方案1】:

    这是另一种说法。

    假设您的算法在问题大小的位数上是线性的。所以,也许你有一个新的算法来分解一个大数,你可以证明它在位数上是线性的。因此,使用您的算法计算 20 位数字所需的时间是 10 位数字的两倍。这将具有日志复杂性。 (这对发明者来说是值得的。)

    二分法具有相同的行为。将区间长度缩短 1024 = 2^10 大约需要 10 个二等分步骤,但只需 20 步即可将区间长度缩短 2^20 倍。

    日志复杂性并不总是意味着算法在所有问题上都很快。 O(log(n)) 前面的线性因子可能很大。所以你的算法在小问题上可能很糟糕,直到问题规模明显大到其他算法以指数(或多项式)死亡时才会变得有用。

    【讨论】:

    • 用大问题的规模很好地解释了。
    【解决方案2】:

    不确定这是否是您的意思,但是...当您使用像平衡二叉树这样的分散数据结构时,通常会出现对数复杂性,该结构包含 1 个根节点、2 个子节点、4 个子节点孙子、8 个曾孙等。基本上在每个级别上,节点的数量都会乘以某个因子 (2),但迭代中仍然只涉及其中一个。或者作为另一个例子,一个循环,其中索引在每一步都翻倍:

    for (int i = 1; i < N; i *= 2) { ... }
    

    类似的东西是对数复杂度的特征。

    【讨论】:

    • +1 非常有趣。我正在寻找更多类似你的例子的东西。算法对数是否为:for (int i = BIG_number; i > N; i *= 1/2) { ... }
    • 1/2 在整数除法中为零,但如果您使用 "i /= 2" 代替,是的。 (如果这是您想知道的特定算法,最好将其包含在您的问题中。)
    【解决方案3】:

    如果您只是想了解对数 Big Oh,请留意您的数据在每个重复步骤中何时减半。

    这是因为如果您正在处理的数据是前一步的 1/2,那么它就是一个无限序列。

    【讨论】:

    • 通常在谈到大 O 时,log 表示对数基数 2。
    • @samoz,对数与底数无关。 log_a(x) = log_b(x)/log_b(a) 从基数 a 转换为基数 b。
    • @George 同意,但通常是基数 2。
    【解决方案4】:

    不严格,但如果你有一个算法,基本上将每次迭代需要完成的工作分成一半,那么你就有对数复杂度。经典的例子是二分查找。

    【讨论】:

    • 不一定。我理解你试图暗示的意思,但仅仅因为你将工作分成两半并不意味着你得到对数复杂度,你甚至可以有指数时间来处理这件事。你必须注意解决方案是如何重新组合的,以及分裂的问题是如何得到解决的。在很多情况下,重组步骤占主导地位。请参阅 Master Theorem 或更好地解决没有定理的递归。一个简单的复现之下,有很多惊喜。
    • @unjaan:我认为你误会了我。我不只是说将工作分成两半,而是说“每次迭代都需要将工作分成一半”。我的意思是,如果与上一步相比,每一步都有一半的工作要做,那么你就有对数复杂度(对于工作,读取计算)。
    【解决方案5】:

    Master theorem 通常有效。

    【讨论】:

    • 有点难想,但一旦掌握就很好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多