有没有一个函数可以交换c++向量中的两个段

Is there a function to swap two segment in a c++ vector?

本文关键字:两个 向量 函数 有一个 c++ 交换      更新时间:2023-10-16

我知道有一个std::swap可以交换向量中的两个元素,或者迭代交换两个相同长度的段。例如,我可以写一个循环来交换向量abcdefgh中的bcdefg,从而得到aefgbcdh。但是我可以交换bcdef(不同长度)吗?或者std::vector中是否有其他功能可以实现这一点?

如果线段相邻,则可以使用std::rotate。例如:

std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

假设我想把{ 1, 2, 3 }换成{ 4, 5, 6, 7 }。我可以做到:

std::rotate(v.begin() + 1, v.begin() + 4, v.begin() + 8);

如果线段不相邻,可以使用rotate两次,但它可能会做超出严格要求的工作。例如,用{ 4, 5, 6, 7 } 交换{ 1, 2 }

std::rotate(v.begin() + 1, v.begin() + 4, v.begin() + 8);
std::rotate(v.begin() + 5, v.begin() + 7, v.begin() + 8);

这将减少为等长间隔交换,然后进行旋转。

等长间隔交换将问题减少为"将一个间隔移动到另一个点",这可以用std::rotate就地实现。

如果半开间隔[a,b)正向x移动,则:

std::rotate( a,b,x );

如果向后移动到y,则:

std::rotate( y,a,b );

如果我们假设我们可以按正确的顺序得到区间(序列中右边之前的左边区间),那么我们可以这样做:

template<class I>
void swap(I a, I b, I x, I y){
  using std::distance; using std::next; using std::advance;
  auto d_ab=distance(a,b);
  auto d_xy=distance(x,y)
  auto d=(std::min)(d_ab,d_xy);
  std::swap_ranges(a,next(a,d),x);
  advance(a,d);
  advance(x,d);
  if (a==b){
    std::rotate(b,x,y);
  }else{
    std::rotate(a,b,x);
  }
}

可以进行避免多次遍历元素的微观优化,但对于向量迭代器来说,额外的进步应该是免费的。

一个工业级的迭代器会进行标记调度,为随机访问迭代器编写一个光滑的迭代程序,而其他迭代器则会进行双迭代器循环交换元素(限制检查的手动交换范围),最后使用类似的rotate

如果我们不知道顺序是abxy,我们需要随机访问迭代器(并获得对<的访问)。然后我们需要包装上面的std::rotate调用来更改参数的顺序。

通过访问end迭代器,我们仍然可以使用前向迭代器来高效地完成它。

void swap(std::vector<int>& v, int start1, int end1, int start2, int end2)
{
    int size2 = end2 - start2 + 1;
    int size1 = end1 - start1 + 1;
    auto begin = v.begin() + start1;
    auto end = v.begin() + end2 + 1;
    std::rotate(begin, v.begin() + start2, end);
    std::rotate(begin + size2, begin + size2 + size1, end);
}

这是一个使用双旋转技巧完成工作的通用版本:)