STL approaches for given loop - c++

this loop works fine as expected. however is there any STL approach to mimic the exact functionality as the example below?
for (auto i = vec.size() - 1; i > 0; --i)
{
vec[i] = vec[i - 1];
}

Rather than an insertion or a rotate, all we're doing here is copying, so it seems like the thing to use is a copy. We could do the job with reverse_iterators:
std::copy(f.rbegin() + 1, f.rend(), f.rbegin());
...or with the algorithm really intended specifically for this sort of situation, std::copy_backward:
std::copy_backward(f.begin(), f.end()-1, f.end());
Either way, it's simple, straightforward, and about as efficient as possible (almost certainly more efficient than using insert/pop or rotate/assign).

std::rotate:
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt n_first, ForwardIt last );
Used as (for a vector v)
// rotation left
std::rotate(v.begin(), v.begin() + 1, v.end());
// example:
// initial v: 1 2 3 4 5
// after rotate: : 2 3 4 5 1
// rotation right (as in your "script")
std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());
// example:
// initial v: 1 2 3 4 5
// after rotate: 5 1 2 3 4
//now if you do this,then it'll have the same effect as your code.
v[0] = v[1];
//before assignment: 5 1 2 3 4
//after assignment: 1 1 2 3 4
The difference w.r.t. your example is that, here, the first element will receive the previously last element (whereas in your code, the first element is untouched).
Performs a left rotation on a range of elements.
Specifically, std::rotate swaps the elements in the range [first,
last) in such a way that the element n_first becomes the first element
of the new range and n_first - 1 becomes the last element.
A precondition of this function is that [first, n_first) and [n_first,
last) are valid ranges.
http://en.cppreference.com/w/cpp/algorithm/rotate

The exact equivalent? Assuming the vector is not empty:
auto val = vec.front(); //Just in case the list is 1 element long.
vec.pop_back();
vec.insert(vec.begin(), val);
Your code effectively does this:
1 2 3 4 5 6
1 1 2 3 4 5
The first element is in two places, while the last element is lost. The above code does the same.

Related

C++ Priority Queue - ordering intervals

Given initially a time interval. Every time, we pick the largest interval and split that into two halves. If there is a tie, then we pick the interval with the lowest starting point.
for example - [0,9]
first split - P1 [0,4] and P2 [4,9]
For second split :
dist(P1) = 3 => if pick P1, new intervals would be [0,2] and [2,4].
dist(P2) = 4 => if pick P2, new intervals are [4, 6] and [6,9]
In both the cases, we have to create sub interval of distance 1. So, it's a tie. and, we pick P1 as P1 < P2.
[0,2], [2, 4], [4, 9]
Third Split:
[0,2], [2, 4], [4,6], [6,9]
Fourth Split:
There is a tie, s0, picked [0,2]
[0,1], [1,2], [2,4], [4,6], [6, 9]
Fifth Split:
[0,1], [1,2], [2,3], [3,4], [4,6], [6,9]
a possible candidate to be on the top : [4,6]
But, I always get [1,2] on top.
#include <iostream>
#include <queue>
using namespace std;
int main()
{
auto dist{ [](const auto & p) {
return p.second - p.first - 1;
} };
auto comp{
[&dist](const auto & p1, const auto & p2) {
if (abs(dist(p1) - dist(p2)) <= 1) {
return p1.first > p2.first;
}
return dist(p1) < dist(p2);
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> maxQ{comp};
maxQ.push({ 0, 9 }); // initial interval
for (int i{ 0 }; i < 5; ++i) {
auto ii{ maxQ.top() };
maxQ.pop();
int mid = (ii.first + ii.second) / 2;
maxQ.push({ ii.first, mid });
maxQ.push({ mid, ii.second });
}
while (!maxQ.empty()) {
auto& ii{ maxQ.top() };
cout << ii.first << " : " << ii.second << endl;
maxQ.pop();
}
}
I'm getting the following output :
1 : 2
6 : 9
0 : 1
2 : 3
3 : 4
4 : 6
IMO, 1 : 2 interval shouldn't be on top. Could someone help me here, why is it so.
It turns out that this issue has more to do with how priority queues comparators are designed, refer to The reason of using `std::greater` for creating min heap via `priority_queue`
The gist of it is that when two nodes are compared, if the comparator returns true, p1 will fall below p2. So a basic ">" comparator, will have smaller nodes at the top, and bigger nodes at the bottom.
To visualize the issue, I ran through it in a debugger, this is the moment at which the (1,2) is being put above (6,9). This is the current state of the priority queue:
2 : 4
6 : 9
4 : 6
0 : 1
1 : 2
We see that (2,4) is in front (6,9), which is expected since our comparison function says that (2,4) < (6,9) as explained above.
Then, the code goes to pop the top of the priority queue, meaning replaces (2,4) with the new biggest interval. How priority queues in C++ do this, is they swap the first element and last elements of the heap, and then reduce the size of it by 1 (so we lose the original first element).
So after the swap and size reduction, our heap looks like this:
1 : 2
6 : 9
4 : 6
0 : 1
Then, since the previously deemed smallest element is now at the top of the queue, we need to find its rightful spot.
So (1,2) is going to look at its children, (6,9) and (4,6), and see which is more important.
With our comparison operator, (4,6) is the more important node.
It then compares, (1,2) with the most important of the previous two nodes, (4,6), to see if it needs to perform a swap to make the queue valid.
It then finds that (1,2) is more important because 1 < 4. Thus, (1,2) stays in its spot and we're left with:
1 : 2
6 : 9
4 : 6
0 : 1
We can plainly see that [1,2] is ordered before [4,6], by plugging it into your comparator:
comp([1,2], [4,6])
if (abs(dist([1,2]) - dist([4,6])) <= 1) { // abs(0 - 1) <= 1 or 1 <= 1
return 1 > 4; // false
}
return dist([1,2]) < dist([4,6]); // not reached
Only you can correct the comparator to achieve whatever your goal is here, but the existing code is wrong if you want [1,2] to be ordered after [4,6].
At a guess, though, based on your description, you might try:
if (abs(dist(p1)) == abs(dist(p2)))
But I'd go to some lengths to ensure that your ordering is strict weak as it must be for the container. Sprinkling some more abs around may help.
Overall this is quite a complex comparator that's not easy to understand at a glance.
I think It is because the ordering of intervals is not strict.
e.g. P1(0,1), P2(4,6) and P3(6,9)
P1 should come before P2.
P2 should come before P3.
P3 should come before P1.
That's crazy. How could I set a strict pair ordering here?

Upper/lower bounds don't work as I expect, can not understand why

Here is the code. As a result I get "4 4". Don't understand why it is not "2 4" (according to lower and upper bounds' defenitions).
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> v = {1, 2, 4, 5};
vector<int>::iterator s , f;
s = lower_bound(v.begin(), v.end(), 3);
f = upper_bound(v.begin(), v.end(), 3);
cout << (*s) << " " << (*f);
return 0;
}
From std::lower_bound:
Returns an iterator pointing to the first element in the range
[first,last) which does not compare less than val.
The first element (from the beginning of the vector) which is not less than 3 is 4 and hence lower_bound returns 4.
From std::upper_bound:
Returns an iterator pointing to the first element in the range [first,last) which compares greater than val.
The first element (from the beginning of the vector) which is greater than 3 is 4 and hence upper_bound returns 4.
The reason for this confusion is because upper_bound returns the first element that is greater than the given value, so by symmetry we expect lower_bound to return the last element (from the beginning of the vector) that is less than the given value. But alas, the std function doesn't obey this "expected" symmetry.
It would be easier to understand/remember what std::lower_bound() and std::upper_bound() return knowing that std::equal_range() returns a pair of iterators, where the first one is equal to what std::lower_bound() returns, and the second one is equal to what std::upper_bound() returns.
So, here are different cases when they are called with a parameter of 4:
1 2 3 4 4 4 4 5 E
| |
F S - first points to the first element, second to the one behind last, representing range which contains 4
1 2 3 4 5 E
| |
F S same for one element
1 2 3 4 E
| |
F S same as before, but 4 is the last element
1 2 3 5 E
|
F==S first == second, which means range for elements equal to 4 is empty
1 2 3 E
|
F==S same as before but there is no element greater than 4
Where E means what container.end() returns - an iterator behind the last element.
The naming of lower_bound and upper_bound is unfortunate as it invites confusion. The names refer to the results when searching through a sequence that has multiple elements that are exactly equivalent to the one you're searching; lower_bound returns the iterator to the start, and upper_bound returns one past the end.
When the element isn't part of the sequence, they both return an iterator to the first element greater than the one you were searching for. This might be the end iterator if there are none greater.

Remove last occurrence of an element in a vector STL

How can I remove only the last occurrence of a value in a C++ vector?
I have this pice of code.
if(vect.erase(std::remove(vect.begin(), vect.end(), oldVal),vect.end()) == vect.end()){
cont++;
}
vect.push_back(newVal);
It removes all instances of a value in the array. I need it to remove only the last specific element in the vector.
Example
Vector: 1 3 4 5 3 5 3 8 3 6
End I want to remove a '3' then should get:
1 3 4 5 3 5 3 8 6
Is there any canonical solution or should I try a stack os list?
std::find will find an element
std::reverse_iterator, accessed by myVector.rbegin() allows you to search from the back.
erase() as above.
Something like:
auto foundIt = std::find(vect.rbegin(), vect.rend(), oldVal);
// Find first from the back, i.e. last
if (foundIt != vect.rend()) { // if it was found
// get back to the right iterator
auto toRemove = --(foundIt.base());
// and erase it
vect.erase(toRemove);
}

Shifting values of a vector in C++

Assuming the following basic vector:
std::vector<int> numbers;
numbers.push_back(0);
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
What is an efficient way to insert 6 new numbers in between 0 and 1?
Here is my approach right now, but I feel like it's not very efficient:
for (int new_number=0;new_number<6;new_number++) {
numbers.emplace(numbers.begin()+1+new_number,new_number);
}
The reason I don't like this approach is that numbers 1-3 have to be moved 6 times. Is there a way to move these numbers just once instead of doing it 6 times? Then I can use this loop:
for (int new_number=0;new_number<6;new_number++) {
numbers[new_number+1]=new_number;
}
Here is what I am trying to accomplish:
Vector Before Shifting:
0 1 2 3
Vector After Shifting:
0 X X X X X X 1 2 3
There is an overload of the insert function that lets you insert n identical items:
// Add six copies of -1 to the vector starting at position 1
numbers.insert(numbers.begin()+1, 6, -1);
You can use another overload that takes three iterators - the iterator where to insert, and a begin/end pair of iterators from where to take the data:
// Insert addedNUmbers at position 1
numbers.insert(numbers.begin()+1, addedNUmbers.begin(), addedNUmbers.end());
If you must insert items one-by-one from disparate sources, so you can't use the range-insertion, one option is to insert everything at the back, and then use std::rotate:
#include <algorithm>
v.reserve(v.size() + 6);
v.push_back(12);
v.push_back(foo());
// ...
std::rotate(v.begin() + 1, v.begin() + 4, v.end());
Something like this will insert 6 at the beginning of numbers:
numbers.insert(numbers.begin(), 6);
If you want to insert the number 6 after the number one:
numbers.insert(find(numbers.begin(), numbers.end(), 1), 6);
(Obviously, if you don't KNOW for sure that the number is in the list, you may want to check that before you insert!)

Trouble in understading behaviour of std::transform

Consider this -
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
#include <list>
int main()
{
typedef std::list<int> L;
L l(5);
typedef L::const_iterator CI;
typedef L::iterator I;
CI cb = l.begin(), ce = l.end();
I b = l.begin();
std::transform(cb, --ce, ++b, std::bind2nd(std::plus<CI::value_type>(), 1));
std::copy(l.begin(), l.end(), std::ostream_iterator<CI::value_type>(std::cout\
));
std::cout<<std::endl;
return 0;
}
Acccording to me its output should be 01111 as transform will iterate from first to "second last" element of list add 1 to each element and overwrite from "2nd" to "last" element.
But to my surprise output is 01234
What am I missing ? I read the documentation of transform on cppreference
This is because your are storing the result of each individual transformation into the next element of the source container, so the next input of the transform function will be the output of the previous transform (because of how you defined the input and output ranges).
In other words, the transform() algorithm will process the first element of your container (0), add 1 to it, and store the result (1) as the second element of that same container. Then, it will process the second element, which is now 1; it will add 1 to it, and store the result (2) as the third element of the container. And so on until you get to the last iteration.
If you want to get the output 01111, you should either store the result of the transform into a diffferent container (live example):
std::vector<int> out(l.size());
std::transform(cb, --ce, ++out.begin(),
// ^^^^^^^^^^^^^
std::bind2nd(std::plus<CI::value_type>(), 1));
Or use a different iteration strategy, as suggested by DyP in the comments (live example):
std::transform(++cb, ce, ++b, std::bind2nd(std::plus<CI::value_type>(), 1));
Since you are starting to add elements into the same container at ++b, there is an off by one offset, which means that you insert element i plus 1 into position i+1. So you are accummulating the sum as you move along. Assuming transform processes the elements sequentially, this is what the first three iterations will do:
0 0 0 0 0
Add 1 to position 0, put it in position 1
0 1 0 0 0
Add 1 to position 1, put it in position 2
0 1 2 0 0
Add 1 to position 2, put it in position 3
0 1 2 3 0