Wellen
Wellen

Reputation: 61

add at beginning and end of vector

Which is the smartest way to add at the beggining of a vector the last two elements of the vector itself and add at the end of the vetor the first two element of the vector? I mean, if my starting vector is

v = 1 2 3 4 5 6 7 8 9

I need that it becames

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

Upvotes: 0

Views: 869

Answers (3)

Markus
Markus

Reputation: 592

By using the vector::insert function for ranges. It is easier to first insert the first two elements at the end.

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

Edit: Is undefined behaviour.

Appending std::vector to itself, undefined behavior?

Upvotes: 0

Steve Jessop
Steve Jessop

Reputation: 279245

First, if the container is going to be large then consider using deque instead of vector. It's more efficient for adding at the start.

For vector you can't insert elements out of the vector to the start because the first thing that happens is everything in the vector gets moved (and all iterators and references to those elements are invalidated). So you either need to copy the elements out of the vector or you need to put insert elements at the start and then copy-assign to them. Assuming the type is int, I'll go with the former:

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);
}

Alternatively, this uses more memory but might be easier to read. As a bonus it gives the strong exception guarantee even with types whose copy constructor can throw. My code above can be made to offer the strong guarantee by adding a call to reserve, but only because int is a trivial type:

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);
}

For deque you don't need to store any elements outside the container provided you use a reference instead of an iterator to access them. Again this only offers the basic exception guarantee.

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));
}

Upvotes: 5

Vlad from Moscow
Vlad from Moscow

Reputation: 310950

My five cents

    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;

Upvotes: 2

Related Questions