std::向量中的值传播
value propagation in a std::vector
如果我有一个像这样初始化的std::vector
:
0 1 2 3 4 5
如何最好地将4传播到第一个位置?也就是说,我想要处于这种状态的std::vector
:
4 0 1 2 3 5
取出4并重新插入可能会很昂贵,因为我相信前面的插入是O(N)
。我想交换连续位置的值(比如在冒泡排序中),但这也是O(N)
。使用另一个容器(如std::list
)是唯一的方法吗?
编辑:在看到一些混乱之后,让我澄清一下,我的目标是在std::vector
中另一个已知位置的值之前,在std::vector
中的已知任意位置预加一个值。
即使有一个可接受的答案,正常的C++方法也是使用提供的算法。在这种情况下,应该是std::rotate
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator> // for std::advance
int main(int argc, char** argv) {
std::vector<int> v = { 0, 1, 2, 3, 4, 5 };
std::cout << "Before: ";
for (auto element : v)
std::cout << element << " ";
std::cout << std::endl;
// edit starts here
auto first=v.begin();
auto nfirst=first;
std::advance(nfirst, 4); // Iterator of first element to move to front
auto last=nfirst;
std::advance(last, 1); // 1 is element count for moving to front
std::rotate(first, nfirst, last);
// edit ends here
std::cout << "After: ";
for (auto element : v)
std::cout << element << " ";
std::cout << std::endl;
return 0;
}
编辑:在与Luc Touraille讨论后,我看到了改进的空间。现在,该解决方案使用std::advance
进行迭代器操作。因此,它应该与std::rotate
所需的前向迭代器一起工作。
如果O(N)是一个问题,则更改容器(例如std::deque)是唯一的选项。
然而,一定要确保O(N)真的是一个问题!
说真的,我非常怀疑O(n)在实际代码中是否真的有问题。使用std::vector
而不是std::list
有更好的理由,比如比使用big-O更好的内存局部性和更少的内存开销。但是,您仍然可以优化标准方法(尽管要求dst
在src
之前)
std::vector<int>::iterator src = ..., dst = ...;
...
auto tmp = std::move(*src);
vec.erase(src);
vec.insert(dst, std::move(tmp));
通过将两个O(n)遍历(在erase
中向左移动一次,在insert
中向右移动一次)变成一个(可能更小)遍历:
auto tmp = std::move(*src);
for(auto iter=src; iter!=dst; --iter)
*iter = std::move(*std::prev(iter));
*dst = std::move(tmp);
编辑:不过请注意,我上面的代码片段只不过是不必要地复制了Jan在他的回答中提出的std::rotate
。
除了@JanHerrmann提供的出色答案外,这里还有一个用于在一个范围内移动元素的通用函数:
#include <algorithm>
#include <iostream>
#include <iterator>
// Moves the element src before dst, maintaining the order of other values
template <typename RandomAccessIt>
void moveElement(RandomAccessIt src, RandomAccessIt dst)
{
if (dst == src)
{
return;
}
if (dst < src)
{
std::rotate(dst, src, src + 1);
}
else
{
std::rotate(src, src + 1, dst);
}
}
void printVector(const std::vector<int> &v)
{
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << 'n';
}
int main() {
std::vector<int> v = { 0, 1, 2, 3, 4, 5 };
printVector(v); // 0 1 2 3 4 5
moveElement(v.begin() + 4, v.begin());
printVector(v); // 4 0 1 2 3 5
moveElement(v.begin() + 2, v.begin() + 2);
printVector(v); // 4 0 1 2 3 5
moveElement(v.begin() + 2, v.begin() + 3);
printVector(v); // 4 0 1 2 3 5
moveElement(v.begin() + 2, v.end());
printVector(v); // 4 0 2 3 5 1
}
- 为什么可以将左值传递给"std::async",即使它引用了右值
- 当值传递给C++中的运算符重载函数时会发生什么
- 如何将非可变参数值传递给 fmt::format?
- 将 qml 项目值传递给 cpp 后如何与它们进行交互?
- NDK:将文本字段值传递给 c++ 字符串
- 如何将值传递给 lambda 函数
- 如何在C++中将std::string值传递给RegSetValueEx()
- 如何将 c ++ 变量的值传递给 hadoop HDFS 的 bash 系统命令?
- C++ 通过参数将值传递给 char 数组
- 如何将值传递给MFC消息映射函数on_command
- 使用JNI将长值传递给Java
- 如何在不使用 Argv 和 Argc 的情况下将 Sum 值传递给 C++ 程序
- C++ 将值传递给 fStream
- 如何将函数中的多个值传递给C++中的不同函数
- 将多个解析值传递给 addPositionalArgument 函数
- C++为什么将左值传递给move构造函数对模板有效
- 一种自动检测对象的方法,该方法通过值传递给c++中的函数
- 将值传递给main(int,char**)
- 将大于long类型的最大值的值传递给C中的fseek
- 将值传递给atexit