我知道有std::swap
可以在向量中交换两个元素,或者迭代交换两个长度相同的段。例如,我可以编写一个循环来交换向量bcd
中的efg
和abcdefgh
,从而生成aefgbcdh
。但我可以交换bcd
和ef
(不同长度)吗?或者std::vector
中是否还有其他可以实现此功能的功能?
答案 0 :(得分:6)
如果细分相邻,您可以使用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
两次来完成,但它可能会比严格必要的工作更多。例如,将{ 1, 2 }
与{ 4, 5, 6, 7 }
std::rotate(v.begin() + 1, v.begin() + 4, v.begin() + 8);
std::rotate(v.begin() + 5, v.begin() + 7, v.begin() + 8);
答案 1 :(得分:3)
这减少到等长的间隔交换,然后是旋转。
等长间隔交换减少了“将间隔移动到另一个地点”的问题,可以使用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
at结束。
如果我们不知道订单是a
,b
,x
,y
,我们需要随机访问迭代器(并获得{{1}的访问权限}})。然后我们需要包含上面的<
调用来改变参数的顺序。
通过访问std::rotate
迭代器,我们仍可以使用前向迭代器进行效率低下。
答案 2 :(得分:1)
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);
}
这是使用双旋转技巧完成工作的通用版本:)