【问题标题】:add at beginning and end of vector在向量的开头和结尾添加
【发布时间】:2014-01-30 23:23:55
【问题描述】:

在向量的开头添加向量本身的最后两个元素并在向量的末尾添加向量的前两个元素的最聪明的方法是什么? 我的意思是,如果我的起始向量是

v = 1 2 3 4 5 6 7 8 9

我需要它变成

v = 8 9 1 2 3 4 5 6 7 8 9 1 2

【问题讨论】:

  • vector::insert() 对你来说还不够吗?
  • 你想实现像周期性边界这样的东西吗?如果是,最好在索引上应用模运算符。
  • @Markus 是的,但我需要 MPI_Send 这个向量,我认为这是继续我的代码的更简单方法
  • 我不知道 MPI_Send 是什么,但你可能会陷入陷阱,因为修改一个值不会同步其他值。
  • 请记住,这些条目是完全独立的。

标签: c++ vector


【解决方案1】:

首先,如果容器会很大,请考虑使用deque 而不是vector。在开始时添加更有效。

对于vector,您不能将元素从vector 插入到开头,因为首先发生的事情是向量中的所有内容都被移动(并且所有迭代器和对这些元素的引用都无效)。因此,您要么需要从向量中复制元素,要么需要将插入元素放在开头,然后复制分配给它们。假设类型是int,我会选择前者:

if (v.size() >= 2) {
    int tmp[] = {*(v.end() - 2), *(v.end() - 1)};
    v.insert(v.begin(), tmp, tmp + 2);
    tmp[0] = v[2]; tmp[1] = v[3];
    v.insert(v.end(), tmp, tmp + 2);
}

或者,这会使用更多内存,但可能更容易阅读。作为奖励,即使对于复制构造函数可以抛出的类型,它也提供了强大的异常保证。我上面的代码可以通过添加对reserve 的调用来提供强有力的保证,但这只是因为int 是一个平凡的类型:

if (v.size() >= 2) {
    std::vector<int> new_v;
    new_v.reserve(v.size() + 4);
    new_v.insert(new_v.end(), v.end() - 2, v.end());
    new_v.insert(new_v.end(), v.begin(), v.end());
    new_v.insert(new_v.end(), v.begin(), v.begin() + 2);
    v.swap(new_v);
}

对于deque,您不需要在容器外存储任何元素,只要您使用引用而不是迭代器来访问它们。同样,这仅提供基本的异常保证。

if (v.size() >= 2) {
    v.push_front(v.back());
    v.push_front(*&(v.end() - 1));
    v.push_back(*&(v.begin() + 2));
    v.push_back(*&(v.begin() + 3));
}

【讨论】:

  • 你能安全地将一系列迭代器从一个向量插入到它自身吗?我以为那是UB。
  • @SteveJessop 您的代码无法按我的意愿工作,输出为6 7 1 2 3 4 5 6 7 8 9 1 2,而vector 部分中没有添加行。我需要那条线吗?
  • @SteveJessop 感谢您的帮助,但是我需要使用矢量,并且您的代码不适用于 reserve
  • @SteveJessop 现在可以了,这是更简单的方法吗?你能解释一下为什么马库斯的答案是错误的吗?
  • @SteveJessop:我认为即使在最后也是 UB,因为如果向量需要调整大小,那些迭代器就会失效。
【解决方案2】:

我的五分钱

    std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    v.insert( v.end(), { v[0], v[1], v[v.size() - 2], v[v.size() - 1] } );
    std::rotate( v.begin(), std::prev( v.end(), 2 ), v.end() );

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

【讨论】:

  • rotate 在这里并不直观,但它确实很好用!
  • 来自莫斯科的 @Vlad 您的代码可以与 c++ 一起使用吗?还是只使用 c++11?
  • @Mooing Duck 我想展示一些原创的东西。:)
  • @Wellen:这里使用 C++11
  • 您可以或多或少地在 C++03 中执行此操作,但将值显式复制到数组中(就像我的回答一样,但是 4 个元素而不是 2 个)。初始化器列表更好,因为它永远不必提及向量的value_type
【解决方案3】:

通过使用vector::insert 函数获取范围。在末尾插入前两个元素更容易。

v.insert(v.end(), v.begin(), v.begin()+2);
v.insert(v.begin(), v.end()-2, v.end());

编辑: 是未定义的行为。

Appending std::vector to itself, undefined behavior?

【讨论】:

  • 未定义的行为,迭代器在被读取之前可能会失效
  • 我确实想到了这一点,因此阅读了 cplusplus.com 上的 vector::insert 参考资料。我没有找到提示,它是UB。但你是对的,它是未定义的行为! Discussed here 如果源迭代器属于目标容器,则您违反了先决条件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
相关资源
最近更新 更多