【问题标题】:Why is std::rotate faster than this way of doing it?为什么 std::rotate 比这种方式更快?
【发布时间】:2021-06-10 23:05:04
【问题描述】:
void rotate(vector <int> &a)
{
    int lastElem = a[a.size()-1];
    
    for(int i=a.size()-1;i>0;i--){
       a[i] = a[i-1];
    }
    
    a[0] = lastElem;
}

对比

rotate(a.begin(),a.end()-1,a.end());

据我所知,上面的算法是 O(n) 那么为什么 STL 方式更快(我认为它也是线性时间)。

【问题讨论】:

  • 有圆形数组这种东西吗?然后旋转可能是 O(1)。
  • [专业提示] int lastElem = a[a.size()-1]; 可以替换为int lastElem = a.back();
  • STL 可以使用memmove 操作的组合?
  • rotate 交换元素,而您正在复制它们。尽管在int 的情况下,这无关紧要。请包含您的基准测试代码,以证明差异。
  • @AdrianMole 看起来像这样,当 value_type 是 POD 时,GCC 对使用随机访问迭代器调用的 std::rotate 有特殊的实现。它使用某种内部移动功能:github.com/gcc-mirror/gcc/blob/…

标签: c++ algorithm performance stl


【解决方案1】:

std::rotate 的标准库实现很可能使用对 memmove() 的调用来进行批量数据复制。这就是它比您的手写循环更快的原因之一。

由于您只旋转单个元素,您可以通过调用std::copy_backward 来替换循环。这也将编译为 memmove() 并提供更好的性能。

void rotate(std::vector<int> &a)
{
    int lastElem = a.back();
    std::copy_backward(a.begin(), a.end() - 1, a.end()); // memmove()
    a.front() = lastElem;
}

您可以检查生成的程序集here on Compiler Explorer

【讨论】:

  • 请注意,使用-O3 对本示例至关重要(在编译器资源管理器中)。实际上,代码向量化对该操作的最终性能有很大影响,并且 GCC 使用 -O3 自动向量化代码而不是 -O2(而 memmove 是手动向量化的)。
猜你喜欢
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2013-05-22
  • 2021-04-24
  • 2015-01-07
  • 1970-01-01
  • 2021-05-05
  • 2014-10-24
相关资源
最近更新 更多