上限固定时的操作顺序

时间:2013-06-13 07:51:07

标签: c++ algorithm bit-manipulation

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

#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)。

我错了吗?

5 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:2)

我将为上述问题添加更好的解决方案。

在循环中使用以下步骤

x = x & (x-1);

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

所以只要有一个ON位,你的循环就会达到最大值。当数字接近0时终止。

因此,复杂性从O(int中的位数)改变为O(on位数)。

答案 2 :(得分:0)

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而不是第一种情况)。

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

应该清除一件事:整数运算的复杂性。在这个例子中不清楚,因为你在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分析根本就没有意义,因为它基于变量长度的输入数据,比如更多,几乎任何长度的数据都是无穷大。 / p>