比特计算算法(Brian Kernighan)的整数时间复杂度

时间:2012-09-12 02:31:58

标签: algorithm bit-manipulation

有人可以解释为什么Brian Kernighan的算法需要O(log N)来计算整数中的设置位(1s)。该算法的简单实现如下(在JAVA中)

int count_set_bits(int n){
    int count = 0;
    while(n != 0){
        n &= (n-1);
        count++;
    }
    return count;
}

我理解它是如何工作的,一个接一个地清除最右边的设置位,直到它变为0,但我只是不知道我们如何得到O(log N)。

3 个答案:

答案 0 :(得分:23)

该算法经历与设置位一样多的迭代。因此,如果我们有一个只有高位设置的32位字,那么它只会循环一次。在最坏的情况下,它每位传递一次。整数n具有log(n)位,因此最坏的情况是O(log(n))。这是你的代码注释的重要位(双关语):

  int count_set_bits(int n){
        int count = 0; // count accumulates the total bits set 
        while(n != 0){
            n &= (n-1); // clear the least significant bit set
            count++;
        }
  }

答案 1 :(得分:6)

N中存在floor(lg(N))+ 1个有效位 - 这是基数2的对数。 n中的1位数最多为此。所以时间渐近上限为O(lg(N))= O(log(N))。

答案 2 :(得分:4)

这个问题实际上是关于大O符号中N的含义,而不是算法的复杂性。

N表示数据的大小。但是,如果“数据”是单个数字,您需要定义您理解的数据大小。它的表示的数量或长度的值。

IMO算法是O(N)。因为在这个以二进制表示IMO计数1的问题中,相关的数据大小是数字表示的长度,而不是它的值,即比特流的长度。显而易见的最坏情况是1次采用N次迭代。

但是如果你将N的值视为数据的大小,它的表示具有log(N)长度,所以你可以说它是O(log(N))

PS只有当你为任意高的Ns推广算法时,大O符号才有意义。在这段代码中,N受int大小的限制,所以你可以说它是O(1),因为它最多将是64次循环迭代(对于64位整数)