добавить в начале и конце вектора

0

Какой самый умный способ добавить в начале вектора два последних элемента самого вектора и добавить в конце ветора первые два элемента вектора? Я имею в виду, если мой стартовый вектор

v = 1 2 3 4 5 6 7 8 9

Мне нужно, чтобы это стало

v = 8 9 1 2 3 4 5 6 7 8 9 1 2
  • 1
    Вам не достаточно vector::insert() ?
  • 0
    Хотите ли вы достичь чего-то вроде периодических границ? Если да, то лучше применить оператор модуля к индексу.
Показать ещё 5 комментариев
Теги:
vector

3 ответа

4
Лучший ответ

Во-первых, если контейнер будет большим, то рассмотрим использование 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));
}
  • 0
    Можете ли вы безопасно вставить диапазон итераторов из вектора в себя? Я думал, что это был UB.
  • 0
    @SteveJessop Ваш код работает не так, как я хочу, вывод 6 7 1 2 3 4 5 6 7 8 9 1 2 без добавленной строки в vector части работает. Мне нужна эта линия?
Показать ещё 10 комментариев
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;
  • 0
    вращение здесь не интуитивно понятно, но оно работает хорошо!
  • 0
    @ Влад из Москвы, твой код работает с с ++? или только с с ++ 11?
Показать ещё 5 комментариев
0

Используя функцию vector :: insert для диапазонов. Легче сначала вставить первые два элемента в конец.

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

Изменение: это неопределенное поведение.

Добавление std :: vector в себя, неопределенное поведение?

  • 2
    неопределенное поведение, итераторы могут быть недействительными, прежде чем они будут прочитаны из
  • 0
    Я действительно думал об этом и поэтому прочитал ссылку vector :: insert на cplusplus.com. Я не нашел подсказки, что это UB. Но вы совершенно правы, это неопределенное поведение! Обсуждается здесь. Если исходные итераторы принадлежат целевому контейнеру, вы нарушаете предварительное условие.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню