web-dev-qa-db-ja.com

整数時間の複雑さにおけるビットカウントアルゴリズム(Brian Kernighan)

Brian Kernighanのアルゴリズムが整数のセットビット(1秒)をカウントするためにO(log N)をとる理由を誰かが説明できますか?このアルゴリズムの簡単な実装を以下に示します(Javaの場合)。

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

一番右にあるビットを0になるまで1つずつクリアしていく方法で理解できますが、O(log N)を取得する方法がわかりません。

33
peter

このアルゴリズムは、設定されたビットと同じ数の反復を実行します。したがって、上位ビットのみが設定された32ビットWordがある場合、ループを通過するのは1回だけです。最悪の場合、ビットごとに1回通過します。整数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++;
        }
  }
24
PengOne

Nにはfloor(lg(N))+ 1有効ビットがあります-これは2を底とする対数です。 nの1ビットの数は最大でこれです。したがって、時間には漸近上限がありますO(lg(N)) = O(log(N))。

6
The_Sympathizer

この質問は、アルゴリズムの複雑さではなく、ビッグO表記におけるNの意味についての質問です。

Nはデータのサイズを意味します。しかし、「データ」が単一の数値である場合は、理解するものをデータのサイズとして定義する必要があります。その表現の数または長さの値。

IMOアルゴリズムはO(N)です。バイナリ表現で1を数えるこの問題では、IMOに関連するデータのサイズは数値の表現の長さであり、その値(ビットストリームの長さ)ではありません。そして、明らかに最悪のケースは、すべて1がN回の反復をとることです。

しかし、Nの値をデータのサイズと考えると、その表現はlog(N)の長さを持つため、O(log(N))と言えます。

PSまた、大きなO表記は、任意に高いNのアルゴリズムを一般化する場合にのみ意味があります。このコードでは、Nはintのサイズによって制限されているため、O(1)と言うことができます。これは、最大64ループの繰り返しになるためです(64ビットintの場合)。

4
Łukasz Zephyr