Delete from i-th element of std::multiset to the end - c++

i is k in my code, just used i for the future users.
std::multiset<std::pair<Point::FT, int> > res;
res.erase(res.begin() + k, res.end());
Error:
no match for operator +
How can I achieve this functionality?

Use std::next to advance the iterator k positions
res.erase(std::next(res.begin(), k), res.end());
The reason your code fails to compile is because std::multiset iterators are BidirectionalIterators, so they only implement pre/post increment/decrement operators, so you need to walk the iterator the desired number of positions, which std::next will do for you.

The iterator operator+ requires that it operate on random access iterators, because addition for non-random-access iterators is a linear operation. The iterators used by a multiset are bidirectional, so you can't do direct addition.
#Praetorian answered the question exactly as written, but I'm going to argue that you're trying to solve the wrong problem/asking the wrong question.
If you want to use indexing in your container, you should strongly prefer vector instead (possibly sorted from time to time). Alternately maybe you know the key of the item you want to erase from to the end. Then you can use logarithmic time find to find the iterator and erase from there to the end.
If you actually need a sorted, indexable, ordered container, I would suggest boost::multi_index instead of any standard container.

Related

Container with optimized find like std::map but non associative

I have a big std::vector<int> where I have to get an iterator so that I can call other functions of it, like erase. Looping through the vector to find the element I'm searching for takes a lot of time.
std::map::find() is much faster, but I don't want to allocate memory for the second value which I'm never going to use.
Is there any single-value container with find() or anything that gives me an iterator with similar speed as std::map::find ? I couldn't find any.
You're looking for std::set or std::multiset.
You could use std::unordered_map or use the same std::vector that keeps an order of elements that you could apply standard algorithms for sorted containers as for example std::equal_range.

[] operator for std::list?

I'm in a situation where I cannot use a vector because I use &element[x] then add more items so the pointer is invalidated. The problem is that std::list does not seem to overload the operator [] nor provide an at() method. Therefore the only way I see I could simulate at() is by using an iterator. Is there however a better way to do this?
You should reconsider your design probably.
Trying to emulate operator[] or at for std::list would lead to performance disaster: these operations would take O(N) and not O(1) time as std::list::iterator is Bidirectional iterator, not Random Access iterator. So if you now iterate through container and call[] or at for each element, it would lead to O(N*N) instead of O(N).
That's why these operation are not provided by std::list.
#include <iterator>
std::list<int> l;
std::list<int>::iterator it = l.begin();
std::advance(it, 37);
For non-random-access iterators (like those of list), this will take linear time, of course.
No std::list is a linked list. It is not possible to access one element directly. The only possibility it to iterate over the elements from the beginning.

How can I define operator< for bidirectional iterator?

How can I define operator< for bidirectional iterator? ( list::iterator )
(I would like to use list and not vector.)
You can't do it directly, but you can compute std::distance(x.begin(), it1) and std::distance(x.begin(), it2) and compare those. Given that lists don't have random access, you expect to have to pay the price for such a query by having to traverse the entire list.
Edit: This will perform poorly if both iterators are near the end of the list. If you want to get more fancy, you could write some exploring algorithm that moves outwards from both iterators:
[ .... <-- it1 --> .... <-- it2 --> .... ]
You would basically keep two copies for each, fwd1/rev1 and fwd2/rev2, and you decrement the rev* iterators until you hit x.begin() and advance the fwd* iterators until you hit x.end(). If your iterator pairs are uniformly distributed, this probably has better expected runtime.
Impossible. You might need to walk until end, and for that you need to know the list of origin, which is not encoded in a list::iterator.
(You can make a function object for this purpose, though, which takes the list or origin as a constructor argument. Mind you, finding out whether one iterator is less-than another would take O(n) time.)
You can't do this because you'd have to know the start and/or end of the list in order to make such a comparison. Only random access iterators define operator<.
Supposing ++(list.end()) is not undefined behaviour and equals list.end(), there is a way. But i am not sure of this hypothesis.
If it is valid, you can define a simple algorithm to obtain the result you want.

Complexity of STL max_element

So according to the link here: http://www.cplusplus.com/reference/algorithm/max_element/ , the max_element function is O(n), apparently for all STL containers. Is this correct? Shouldn't it be O(log n) for a set (implemented as a binary tree)?
On a somewhat related note, I've always used cplusplus.com for questions which are easier to answer, but I would be curious what others think of the site.
It's linear because it touches every element.
It's pointless to even use it on a set or other ordered container using the same comparator because you can just use .rbegin() in constant time.
If you're not using the same comparison function there's no guarantee that the orders will coincide so, again, it has to touch every element and has to be at least linear.
Although algorithms may be specialized for different iterator categories there is no way to specialize them base on whether an iterator range is ordered.
Most algorithms work on unordered ranges (max_element included), a few require the ranges to be ordered (e.g. set_union, set_intersection) some require other properties for the range (e.g. push_heap, pop_heap).
The max_element function is O(n) for all STL containers.
This is incorrect, because max_element applies to iterators, not containers. Should you give it iterators from a set, it has no way of knowing they come from a set and will therefore traverse all of them in order looking for the maximum. So the correct sentence is:
The max_element function is O(n) for all forward iterators
Besides, if you know that you're manipulating a set, you already have access to methods that give you the max element faster than O(n), so why use max_element ?
It is an STL algorithm, so it does not know anything about the container. So this linear search is the best it can do on a couple on forward iterators.
STL algorithms do not know what container you took the iterators from, whether or not it is ordered and what order constraints were used. It is a linear algorithm that checks all elements in the range while keeping track of the maximum value seen so far.
Note that even if you could use metaprogramming techniques to detect what type of container where the iterators obtained from that is not a guarantee that you can just skip to the last element to obtain the maximum:
int values[] = { 1, 2, 3, 4, 5 };
std::set<int, greater<int> > the_set( values, values+5 );
std::max_element( the_set.begin(), the_set.end() ); //??
Even if the iterators come from a set, it is not the last, but the first element the one that holds the maximum. With more complex data types the set can be ordered with some other key that can be unrelated to the min/max values.

Is there any reason that the STL does not provide functions to return an iterator via index?

Is there a reason that the STL does not provide functions to return an iterator into a container via an index?
For example, let's say I wanted to insert an element into a std::list but at the nth position. It appears that I have to retrieve an iterator via something like begin() and add n to that iterator. I'm thinking it would be easier if I could just get an iterator at the nth position with something like, std::list::get_nth_iterator(n).
I suspect I have misunderstood the principles of the STL. Can anyone help explain?
Thanks
BeeBand
You can use advance() from the <iterator> header:
list<foo>::iterator iter = advance(someFooList.begin(), n);
list<foo>::iterator iter = someFooList.begin();
std::advance( iter, n);
If the iterator supports random access (like vector) it'll work quite efficiently, if it only supports increasing (or decreasing) the iterator, like list, it'll work but only as well as can be.
std::list is a linked list. So it does not support random access. To get to the nth position in the list, you have to start at the beginning and move through all the nodes until you arrive at n. This is pretty expensive (O(n)), and thus it's bad to have a method that does not suggest this expense. get_nth_iterator(n) implies getting the iterator that points to the nth node is cheap.
std::vector of course supports this directly with the [] operator, because the datastructure supports random access and so this is very inexpensive for it.
std::list isn't random-access container, so there is no reason for accessing n-th element. if you need this, consider using std::vector instead..
Generally, anything that might be costly is made a bit clumsy, so you won't do it by accident. Using your example, with a container that provides random access iterators it would be simply container.begin()+n, but for an std::list (which provides a forward iterator) you'd need to use list.begin() followed by advance().
If you want to get the Nth iterator, chances are that you just shouldn't be using std::list in the first place. Then again, if you started that sentence at "chances", it would remain nearly as true...