我写了一个程序,计算给定输入数字中2的最大幂。例如,26中最大的2的幂是16,因为2 4 是16.这是算法:
uint power2( uint n )
{
uint i = n;
uint j = i & (i - 1);
while( j != 0 )
{
i = j;
j = i & (i - 1);
}
return i;
}
我在分析算法时遇到了一些困难。我知道我们正试图找出Big-Oh,Big-Omega或Big-Theta符号。为了分析算法,我们应该计算基本操作的数量?我的问题是我看到两行可能是基本操作。我在while循环外面看到了行uint j = i & (i - 1)
,我也看到了while循环中的j = i & (i - 1)
。我觉得while循环中的那个是肯定的基本操作,但是while循环之外的那个呢?
我挣扎的另一部分是确定while
循环体的执行次数。例如,如果我们有一个for循环for(int i = 0; i < n; i++) {...}
,我们知道这个循环将执行n
次。或者甚至在while循环while(i < n * n) {... i++}
中,我们知道此循环将运行n * n
次。但是对于这个while循环,它会根据输入而变化。例如,如果您传入的数字是直接击球的2,则while循环将永远不会执行。但是,如果传入一个非常大的数字,它将执行多次。我不知道它会执行多少次才能说实话。这就是我想弄清楚的。任何人都可以帮助我了解此算法的运行情况及其运行次数,例如O(n)
或O(n^2)
等吗?
答案 0 :(得分:9)
这是一个很好的算法示例,当您对其正在做的事情有一个很好的直观理解而不仅仅是通过查看代码本身时,它更容易推理它。
对于初学者,i & (i - 1)
做了什么?如果你用二进制写的数字并从中减去一个,它就会产生
例如,如果我们取二进制数1001000
(72)并减去一,我们得到1000111
(71)。注意如何清除最低有效1位并将其下面的所有位设置为1.
当你和一个号码为i
的{{1}}时,会发生什么?好吧,i - 1
和i
中最不重要的1位以上的所有位都没有变化,但i - 1
和i
在所有位置都不同意,或者在最低位置 - i - 1
中有效1位。这意味着i
具有清除数字i & (i - 1)
中最低1位的效果。
让我们回到代码。请注意,while循环的每次迭代都使用此技术从数字i
中清除一位。这意味着while循环的迭代次数与数字j
中设置的1位数成正比。因此,如果我们让n
表示b
中设置的1位数,则此算法的运行时间为Θ(b)。
为了了解此算法的最佳和最坏情况行为,正如您所指出的,如果n
是2的完美幂,则运行时为O(1)。这就好了。对于最坏的情况,数字n
可以是全1位,在这种情况下,将在数字n中设置Θ(log n)1位(因为,在二进制中,数字n需要Θ(log n) )要写出的位)。因此,最坏情况的运行时间是Θ(log n)。
总之,我们看到了