上界固定时操作的阶数
order of an operation when upper bound is fixed
我最近参加了一次面试,被要求找出所提供的整数的位数。我写的是这样的:
#include <iostream>
using namespace std;
int givemCountOnes (unsigned int X) {
int count =0;
while (X != 0 ) {
if(X & 1)
count++;
X= X>>1;
}
return count;
}
int main() {
cout << givemCountOnes (4);
return 0;
}
我知道有更好的方法,但这不是问题所在。
问题是,这个程序的复杂性是多少?
因为它表示输入的比特数,所以人们说这是O(n),其中n是输入的比特数。
但是我觉得由于上界是sizeof(unsigned int)
,也就是说64位,我应该说顺序是0(1)。
我错了吗?
复杂度为0 (N)。复杂度随所使用的类型(unsigned int
)的大小线性上升。
上界并不重要,因为它可以在将来的任何时候被扩展。这也无关紧要,因为总是有一个上限(内存大小,宇宙中的原子数量),然后所有东西都可以被认为是0(1)。
我将给上面的问题添加一个更好的解决方案。
在Loop
中使用以下步骤x = x & (x-1);
这将每次一个移除最右边的ON位。
所以你的循环将在最大运行,只要有一个ON位。当数字接近0时终止。
因此复杂度从0 (int的位数)提高到0 (on的位数)。
0表示法用于区分n
不同值之间的区别。在这种情况下,n
将是位数,因为(在您的情况下)位数将改变执行计算所需的(相对)时间。所以O(n)是正确的-一个1位的整数需要1个单位时间,一个32位的整数需要32个单位时间,一个64位的整数需要64个单位时间。
实际上,你的算法并不依赖于数字中的实际位数,而是依赖于数字中最高位的位数,但这是另一回事。然而,由于我们通常将0视为"最坏情况",所以它仍然是O(n),其中n是整数中的位数。
我真的想不出任何方法比O更好——我可以想到提高循环迭代次数的方法(例如使用256个条目表,一次处理8位),但它仍然是"更大的数据->更长的时间"。因为O(n)和O(n/2)或O(n/8)都是一样的(只是后一种情况的总时间是前一种情况的1/8)。
大0符号描述了在最坏情况下算法步骤的计数。在这种情况下,最后一位是1。因此,当你传递n个比特数作为输入时,将会有n次迭代/步骤。
想象一个类似的算法,搜索列表中1的个数。复杂度是O(n)其中n是列表长度。根据你的假设,如果你总是传递固定大小的列表作为输入,那么算法复杂度将变成O(1),这是不正确的。然而,如果你在算法中固定位长度:即像for (int i = 0; i < 64; ++i) ...
这样的东西,那么它将具有O(1)复杂度,因为它做了64次O(1)操作,你可以忽略这里的常数。否则O(c*n) = O(n), O(c) = O(1),其中c为常数。
希望这些例子对你有帮助。顺便说一句,有0(1)个解决方案,我记得的时候会贴出来的:)
有一件事需要澄清:对整数进行操作的复杂性。在这个例子中不清楚,当你在int
上工作时,这是你的机器上的自然字长,它的复杂性似乎只有1。
但是o符号是关于大数据量和大任务的,比如说你有一个n位整数,其中n大约是4096左右。在这种情况下,复杂度加法,减法和移位至少是O(n)复杂度,所以你的算法应用于这样的整数将是O(n²)复杂度(n个操作的O(n)复杂度应用)。
不移动整数的直接计数算法(假设一位测试是O(1))给出O(n log(n))复杂度(它涉及对log(n)大小的整数进行最多n次加法)。
但是对于固定长度的数据(这是C的int)大O分析是毫无意义的,因为它基于变量长度的输入数据,更确切地说,几乎任何长度的数据,直到无穷大。
- 为什么在popback()操作之后,它仍然打印完整的矢量
- Ardunio UNO解决了多个重叠的定时器循环
- 重载操作程序时出错>>用于类中的字符串 memebr
- 对字符串进行位操作
- 我可以在 C++ 中的函数体之外进行操作吗?
- MPI突然停止了对多个核心的操作
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 对字符数组中的元素执行逐位操作
- 如何在directx/c++中进行平移/缩放操作
- 逐位操作的隐式类型转换
- 为什么一个向量上的多线程操作很慢
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 位移操作和位掩码未检测到重复字符
- 如何进行特定的位操作?
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 字符串操作 - 字符计数
- 此代码中的操作流程是什么?C/C++.
- 复制和交换习惯用法与移动操作之间的交互
- 像union_这样的 Boost.Geometry 操作如何处理浮点类型的基本不精确性?
- 在 Windows/C++ 上使用多进程应用程序的高精度定时操作