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)を取得する方法がわかりません。
このアルゴリズムは、設定されたビットと同じ数の反復を実行します。したがって、上位ビットのみが設定された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++;
}
}
Nにはfloor(lg(N))+ 1有効ビットがあります-これは2を底とする対数です。 nの1ビットの数は最大でこれです。したがって、時間には漸近上限がありますO(lg(N)) = O(log(N))。
この質問は、アルゴリズムの複雑さではなく、ビッグ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の場合)。