我正在寻找像一个std ::列表,可以一个元素有效地移动到前面一个std容器:
a-b-c-d-e
“b”移动到前:
a-c-d-e-b
有在STD容器无此功能。 为此,我想我必须结合一个捞出push_front功能,但有没有人可以找到一个更好的主意吗?
预先感谢。
我正在寻找像一个std ::列表,可以一个元素有效地移动到前面一个std容器:
a-b-c-d-e
“b”移动到前:
a-c-d-e-b
有在STD容器无此功能。 为此,我想我必须结合一个捞出push_front功能,但有没有人可以找到一个更好的主意吗?
预先感谢。
如果你没有保持其他元素的顺序,那么最简单的解决方案是毫无疑问只是换你想在容器中的第一元素的元素。 这将是有效的与所有容器。
否则, std::list
提供了一个splice
其可用于操作。 像下面,笔者认为:
void
moveToFront(
std::list<MyType>& list,
std::list<MyType>::iterator element )
{
if ( element != list.begin() ) {
list.splice( list.begin(), list, element, std::next( element ) );
}
}
这应该结束了,只有一对夫妇的指针操作,并且没有副本。 在另一方面, std::list
即可(因为它的局域性较差),一般很慢; 我会用非常仔细地衡量天真实施std::vector
,以确保它是一个全球性的胜利。 在这里消除所有副本可能不会是一个双赢,如果迭代找到你想要移动到前面的元素是十次更加昂贵。 (很多这取决于如何昂贵MyType
是复制,这是多么大,如果sizeof(MyType)
是接近页面的大小,或访问MyType
结束访问了很多间接分配对象的,局部性的说法不会举行。)
随着std::vector
,而不是明显的erase
/ insert
void
moveToFront(
std::vector<MyType>& list,
std::vector<MyType>::iterator element )
{
MyType tmp( *element );
std::copy_backwards( list.begin(), std::prev( element ), element );
*list.begin() = tmp;
}
这将导致比较少拷贝erase
(其复制所有以下元素组成) insert
(其也将所有下列元素内,这意味着所有的元素,因为我们在开始插入的)图案。
在std::vector
,你可以使用std::rotate
,具有线性复杂度
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
std::vector<int> v = { 0, 1, 2, 3, 4 };
int main()
{
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
// swap ranges [1, 2) and [2, 5)
auto it = std::next(v.begin(), 1); // O(1)
auto rb = std::next(it);
auto re = v.end();
std::rotate(it, rb, re); // O(N)
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
在一个std::list
,你可以使用成员函数splice
,这(给定的迭代器)具有恒定的复杂性
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
std::list<int> v = { 0, 1, 2, 3, 4 };
int main()
{
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
auto it = std::next(v.begin(), 1); // O(N)
auto rb = std::next(it);
auto re = v.end();
v.splice(it, v, rb, re); // O(1)
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
注 :最后一个元素conventially表示为back
的STL容器,并作为第一个元素front
。 对于std::vector
,获得迭代到一定元件是恒定时间,和交换是线性时间。 对于std::list
,让迭代器是线性时间,但剪接成同一列表是恒定的时间。 然而,矢量的更好的内存缓存行为也很重要,因为这个基准由斯特劳斯表示。
更新 :一些评论提到简单地交换元素:这只适用,如果你想转换abcde
为aecdb
。 在这种情况下,使用std::iter_swap
任何你喜欢的容器上。 对于改造abcde
为acdeb
,使用std::rotate
或list::splice
。