【问题标题】:order of an operation when upper bound is fixed上限固定时的操作顺序
【发布时间】:2013-06-09 12:47:22
【问题描述】:

我最近接受了一次采访,并被要求找出提供的整数位数。我有这样的事情:

#include <iostream>

using namespace std;
int givemCountOnes (unsigned int X) {
  int count =0;
  while (X != 0 ) {
    if(X & 1)
      count++;
   X= X>>1;
  }

 return count;

}

int main() {
cout << givemCountOnes (4);
return 0;
}

我知道有更好的方法,但这不是这里的问题。

问题是,这个程序的复杂性是多少?

由于它用于输入中的位数,人们说这是 O(n),其中 n 是输入中的位数。

但是我觉得由于上限是sizeof(unsigned int) 即64位,我应该说顺序是o(1)。

我错了吗?

【问题讨论】:

  • 我相信有人会编辑它...可能是我,迟早。但是你能试着学习正确拼写单词并正确使用标点符号吗?

标签: c++ algorithm bit-manipulation


【解决方案1】:

复杂度为 O(N)。复杂性随着所使用类型的大小线性增加 (unsigned int)。

上限无关紧要,因为它可以在将来的任何时间扩展。这也无关紧要,因为总是有一个上限(内存大小,宇宙中的原子数),然后一切都可以被认为是 O(1)。

【讨论】:

    【解决方案2】:

    我只会为上述问题添加一个更好的解决方案。

    在循环中使用以下步骤

    x = x & (x-1);
    

    这将一次删除最右边的 ON 位。

    因此,只要有一个 ON 位,您的循环就会最大运行。当数字接近 0 时终止。

    因此复杂度从 O(int 中的位数)提高到 O(on 位数)。

    【讨论】:

      【解决方案3】:

      O 表示法用于说明n 的不同值之间的区别。在这种情况下,n 将是位数,因为(在您的情况下)位数将改变执行计算所需的(相对)时间。所以 O(n) 是正确的——一位整数需要 1 个时间单位,一个 32 位整数需要 32 个时间单位,一个 64 位整数需要 64 个时间单位。

      其实你的算法并不依赖于数字中的实际位数,而是取决于数字中设置的最高位的数量,但那是另一回事。但是,由于我们通常将 O 视为“最坏情况”,因此它仍然是 O(n),其中 n 是整数中的位数。

      而且我真的想不出任何比 O 更好的方法 - 我可以想到提高循环中迭代次数的方法(例如,使用 256 个条目表,并处理 8 个一次位),但它仍然是“更大的数据 -> 更长的时间”。由于 O(n) 和 O(n/2) 或 O(n/8) 都是相同的(只是后一种情况的总时间是第一种情况的 1/8)。

      【讨论】:

      • 我发布了一个稍微好一点的算法。虽然它在大 O 方面仍然没有改变。但它仍然是这个问题的最佳常数优化,特别是对于可变长度整数。
      【解决方案4】:

      大 O 表示法描述了最坏情况下的算法步骤数。在这种情况下,当最后一位有 1 时。因此,当您将 n 位数作为输入时,将有 n 次迭代/步骤。

      想象一个类似的算法,它在列表中搜索 1 的计数。它的复杂度是 O(n),其中 n 是列表长度。根据您的假设,如果您始终将固定大小的列表作为输入传递,那么算法复杂度将变为 O(1),这是不正确的。 但是,如果您在算法中固定位长:即for (int i = 0; i &lt; 64; ++i) ... 之类的东西,那么它将具有 O(1) 复杂度,因为它执行了 64 次 O(1) 操作,您可以在这里忽略常量。否则 O(c*n) 为 O(n),O(c) 为 O(1),其中 c 为常数。

      希望所有这些示例对您有所帮助。顺便说一句,这有 O(1) 的解决方案,我会在我记得时发布它:)

      【讨论】:

      • O(1) 涉及与常量值进行与运算。但是,它仅适用于预先确定的固定宽度整数值(32、64 或 128 位)。通常不适用于任何整数宽度。 (投反对票不是我的)。
      • 似乎有人对我的说法感到困惑,即固定长度的相同算法是 O(1)。 :D
      • 可能 :) 我现在用 +1 反击。在我看来,这个解释很有用。
      【解决方案5】:

      有一点需要澄清:整数运算的复杂性。在此示例中不清楚,因为您使用 int,这是您机器上的自然字长,其复杂性似乎只有 1。

      但是 O-notation 是关于大量数据和大型任务的,比如你有 n 位整数,其中 n 大约是 4096 左右。在这种情况下,复杂度加法、减法和移位至少具有 O(n) 复杂度,因此应用于此类整数的算法将是 O(n²) 复杂度(应用了 O(n) 复杂度的 n 次操作)。

      不移动整数的直接计数算法(假设一位测试是 O(1))给出 O(n log(n)) 复杂度(它涉及对 log(n) 大小的整数最多 n 加法)。

      但是对于固定长度的数据(即 C 的 int),大 O 分析根本没有意义,因为它基于 可变 长度的输入数据,也就是说,几乎任何长度到无穷大的数据。

      【讨论】:

        猜你喜欢
        • 2016-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多