计算使用 C++ std 函数而不是 for 循环的大 O

Posted

技术标签:

【中文标题】计算使用 C++ std 函数而不是 for 循环的大 O【英文标题】:calculating the Big O of using C++ std function instead of for loop 【发布时间】:2019-08-27 20:43:18 【问题描述】:

如果我正在实现一个 for 循环来在数组中的两个索引之间向右移动元素,那么我需要 O(n) 来移动这些元素,但是如果我使用像 std::rotate 这样的库函数会怎样?一步执行,这是否意味着它需要恒定的时间。

喜欢这个例子

vector<int> arr = 1,2,3,4,5,6,7,8,9,10;

int temp = arr[5];

for(int i = 5 ; i >= 3 ; i--)


    arr[i]=arr[i-1];



arr[2] = temp;

所以arr 将是 1,2,6,3,4,5,7,8,9,10

我可以这样做

 rotate(arr.begin()+2,arr.begin()+5,arr.begin()+6);

...这将导致相同的移位数组

但第一个大约需要 3 步,而另一个只有 1 步,是这样吗?

【问题讨论】:

信息found here 好吧,它可能是一行代码,但它仍然需要进行 n 次迭代才能旋转它,例如你可以用你的代码创建一个函数并调用它(它是一行代码,但它不会成功一个常数复杂度函数) 请注意,如果您将“n”定义为 arr 的长度,for(int i = 5 ; i &gt;= 3 ; i--)rotate(arr.begin()+2,arr.begin()+5,arr.begin()+6); 都是 O(1) 以源代码行数衡量的“步骤数”根本没有意义。 @FrançoisAndrieux 是的,这是肯定的,我只是想知道 C++ 编译器是否在调用 rotate 函数时发挥了他的一些黑魔法 【参考方案1】:

std::rotate 具有线性复杂性,因此虽然它可能比您的代码稍快或稍慢,但两者使用的步骤数大致相同。

在这种特殊情况下,std::rotate 很可能实际上使用了更多步骤,因为它被编码为处理任意数量的位置的旋转,这比像您的代码那样总是只旋转一个位置稍微多一点工作。另一方面,旋转一个位置也可能很常见,标准库可以检查这一点,并针对特定情况使用与您类似的代码。

【讨论】:

如果std::rotate 的参数是常量表达式,假设编译器将内联并可能展开循环(如果它是有益的)似乎是合理的。 @FrançoisAndrieux:在这种情况下,问题在于算法,而不是循环展开之类的问题。 std::rotate 的通常实现使用 2N 次交换,其中 N 是旋转的项目数。 我想不清楚我是专门回复第二部分的。如果可以确定步数是一个常数表达式(例如在这种情况下),那么支持 N 大小步的额外开销可能会消失。听起来您将我的评论解释为两种解决方案都是O(N) 的争议。我并不是说优化会改变这一点。 @FrançoisAndrieux:不,我没有争论任何事情,只是指出除了通常的展开等之外,还需要一些额外的工作。相反,如果您旋转的元素数量是恒定的并且可能低于某个阈值,则您实际上必须切换到完全不同的算法。所以从理论上讲,你可以做到这一点是对的——但我还没有看到可以做到这一点的实现,老实说也不希望很快做到。【参考方案2】:

不,它确实需要线性时间。实际时间复杂度是初始节点和最终节点之间的差异。查看 https://en.cppreference.com/w/cpp/algorithm/rotate

【讨论】:

以上是关于计算使用 C++ std 函数而不是 for 循环的大 O的主要内容,如果未能解决你的问题,请参考以下文章

新线程导致问题 C++

C++ for 循环:条件评估

为啥 C 和 C++ for 循环使用 int 而不是 unsigned int?

如何使用 OpenMP 通过 C++ std::list 并行化 for 循环?

使用 C++,尝试使用 for 循环和 std::max 查找向量中的最大单词

c++ 转换和 lambda - 替换 for 循环