以下程序的复杂程度如何?我认为它必须是O(n),因为有一个for循环运行了n次。
这是一个反转给定整数中的位的程序。
unsigned int reverseBits(unsigned int num)
{
unsigned int NO_OF_BITS = sizeof(num) * 8;
unsigned int reverse_num = 0;
int i;
for (i = 0; i < NO_OF_BITS; i++)
{
if((num & (1 << i)))
reverse_num |= 1 << ((NO_OF_BITS - 1) - i);
}
return reverse_num;
}
上述计划的复杂程度如何?有人说实际的复杂性是O(log n),但我看不出原因。
答案 0 :(得分:8)
考虑到您的上述计划,复杂性为O(1)
,因为8 * sizeof(unsigned int)
是常量。您的程序将始终以恒定的时间运行。
但是,如果n
与NO_OF_BITS
绑定,并且您将该数字设为算法参数(情况并非如此),那么复杂性将为O(n)
。
请注意,对于n
位,num
可能的最大值为2^n
,在这种情况下,如果您希望将复杂性表示为允许的最大值的函数num
,复杂度为O(log₂(n))
或O(log(N))
。
答案 1 :(得分:4)
O-notation描述了算法的时间或空间要求如何取决于输入的大小(表示为n
),在n
变得非常大的限制内。输入大小是表示输入所需的位数,而不是这些位可以表示的值的范围。
(正式地,将运行时间为t(n)
的算法描述为O(f(n))
意味着有一些N
和一些C
的常量t(n) <= C*f(n)
所有n > N
)。
此算法为每个输入位执行固定的工作量,因此时间复杂度为O(n)
。它使用与输入大小相同的工作空间reverse_num
(加上一些渐近变小的变量),因此空间复杂度也是O(n)
。
此特定实现对输入大小施加了限制,因此对时间和空间要求设置了固定的上限。一些答案说,不意味着算法是O(1)
。 O符号描述了算法,而不是任何特定的实现,如果在输入大小上加上限,则无意义。
答案 2 :(得分:1)
如果n是输入数,那么NO_OF_BITS是O(log n)(考虑一下:表示二进制数n,需要大约log2(n)位)。
编辑:让我根据其他回复和评论澄清一下。
首先,让n
为输入数字(num
)。澄清这一点非常重要,因为如果我们将n
视为NO_OF_BITS
,我们会得到不同的答案!
该算法概念 O(log n)
。我们需要反转n
的位。表示数字O(log n)
需要n
个比特,并且反转比特涉及每个比特的恒定工作量;因此复杂性为O(log n)
。
现在,实际上,C中的内置类型不能表示任意大小的整数。特别是,在此实现中使用unsigned int
来表示输入,并且此类型限于固定数量的位(在大多数系统上为32)。此外,这个实现选择通过所有32位,而不是仅仅根据需要经历多个位(从最低位到高位1)。由于32是常量,因此技术的实现在O(1)
时间内运行。
尽管如此,算法在概念上O(log n)
,如果输入是2^5
,5
迭代就足够了,如果输入是2^10
,{ {1}}迭代就足够了,如果10
代表的数字范围没有限制,输入为unsinged int
,那么2^1000
迭代就是必要的。< / p>
在任何情况下,此算法都不会1000
(除非我们将O(n)
定义为n
,在这种情况下它是)。
答案 3 :(得分:1)
如果n == num,复杂度是常数O(1),因为循环总是运行固定的次数。空间复杂度也是O(1),因为它不依赖于输入
答案 4 :(得分:0)
你需要清楚n是什么。如果n是num
,那么您的代码当然是O(log n)NO_OF_BITS ~= log_2(n) * 8
。
另外,当你处理固定大小的值时,整个事情是O(1)。当然,如果您将此视为更一般的概念并且可能对其进行扩展,那么可以在更一般的上下文中将其视为O(log n),您希望将其扩展到固定位数之外。< / p>