2014-01-30 3 views
0

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

v = 1 2 3 4 5 6 7 8 9 

мне нужно что becames

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

Является 'вектор :: вставка()' не достаточно для вас? –

+0

Вы хотите добиться чего-то вроде периодических границ? Если да, вам лучше пойти с применением оператора модуля в индексе. – Markus

+0

@Markus да, но чем мне нужно MPI_Отправить этот вектор, и я думаю, что это самый простой способ продолжить мой код. – Wellen

ответ

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. – templatetypedef

+0

@SteveJessop ваш код не работает, как я хочу, выход '6 7 1 2 3 4 5 6 7 8 9 1 2' без добавленной строки в' vector'. Мне нужна эта линия? – Wellen

+0

@SteveJessop спасибо за вашу помощь, однако мне нужно использовать вектор и ваш код dosen't работает с линией 'reserve' – Wellen

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

@ Vlad из Москвы работает ли ваш код с C++? или только с C++ 11? – Wellen

+0

@ Mooing Duck Я хотел показать что-то оригинальное. :) –

0

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

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

Edit: ли неопределенное поведение.

Appending std::vector to itself, undefined behavior?

+2

неопределенное поведение, итераторы могут быть признаны недействительными до того, как они будут считаны с –

+0

. Я действительно подумал об этом и прочитал ссылку: :: insert на cplusplus.com. Я не нашел подсказки, что это UB. Но ты правдиво прав, это Неопределенное Поведение! [Обсуждено здесь] (http://stackoverflow.com/a/14792174/2056153) Если исходные итераторы принадлежат к целевому контейнеру, вы нарушаете предварительное условие. – Markus

Смежные вопросы