views:

206

answers:

4

Hey, I right now have a list of a struct that I made, I sort this list everytime I add a new object, using the std::list sort method. I want to know what would be faster, using a std::multimap for this or std::list, since I'm iterating the whole list every frame (I am making a game).

I would like to hear your opinion, for what should I use for this incident.

+1  A: 

You might consider using the lower_bound algorithm to find where to insert into your list. http://stdcxx.apache.org/doc/stdlibref/lower-bound.html

Edit: In light of Neil's comment, note that this will work with any sequence container (vector, deque, etc.)

Fred Larson
Note that lower_bound will perform poorly on lists due to linear search time. Otherwise +1.
Billy ONeal
@Billy ONeal: No, check the reference. It's O(log n). Presumably uses a binary search.
Fred Larson
@Fred Larson: It's only (log n) with random access iterators. List provides only bidirectional iterators making it linear. It will be a logarithmic number of comparisons but you still need to linearly transverse the list.
Billy ONeal
@Billy ONeal: Ah, I see your point.
Fred Larson
+5  A: 

std::multimap will probably be faster, as it is O(log n) per insertion, whereas an insert and sort of the list is O(n log n).

Depending on your usage pattern, you might be better off with sorted vectors. If you insert a whole bunch of items at once and then do a bunch of reads -- i.e. reads and writes aren't interleaved -- then you'll have better performance with vector, std::sort, and std::binary_search.

Billy ONeal
+1 for citing `vector` (you could have said `deque` too, it could prove better), however I would also suggest `multiset` here, since it does not seem to be a key/value pair.
Matthieu M.
Even if you insert multiple items using std::vector with std::sort will not give you better performance than std:set or std::multimap because the sort will always have O(n log n) (n items in the list) and and inserting k items into a set with n items will have O(k log n), which is better if k is much smaller than n.
MKroehnert
@MKroehnert: That's why I was talking about non interleaved reads and writes. That is, K would be significant in comparison of N. Also keep in mind that `vector` s have MUCH better locality of reference, as well as space efficiency, when compared with maps. All that extra dereferencing that has to go on inside a map isn't considered in theoretical complexity, but it sure has an impact on real code. See Scott Meyers' Effective STL Item 23: Consider replacing associative containers with sorted vectors.
Billy ONeal
@Billy ONeal: I will have a look at that one. Thanks.
MKroehnert
A: 

Generally speaking, iterating over a container is likely to take about as much time as iterating over another, so if you keep adding to a container and then iterating over it, it's mainly a question of picking a container that avoids constantly having to reallocate memory and inserts the way you want quickly.

Both list and multimap will avoid having to reallocate themselves simply from adding an element (like you could get with a vector), so it's primarily a question of how long it takes to insert. Adding to the end of a list will be O(1) while adding to a multimap will be O(log n). However, the multimap will insert the elements in sorted order, while if you want to have the list be sorted, you're going to have to either sort the list in O(n log n) or insert the element in a sorted manner with something like lower_bound which would be O(n). In either case, it will be far worse (in the worst case at least) to use the list.

Generally, if you're maintaining a container in sorted order and continually adding to it rather than creating it and sorting it once, sets and maps are more efficient since they're designed to be sorted. Of course, as always, if you really care about performance, profiling your specific application and seeing which works better is what you need to do. However, in this case, I'd say that it's almost a guarantee that multimap will be faster (especially if you have very many elements at all).

Jonathan M Davis
Algorithmically, it's as long to iterate over one container than another, in general. In practice, due to cache considerations, array-like structures (`vector` and `deque`) are much more efficient.
Matthieu M.
+1  A: 

If you do not need Key/Value pairs std::set or std::multiset is probably better than using std::multimap.

Reference for std::set: http://www.cplusplus.com/reference/stl/set/

Reference for std::multiset: http://www.cplusplus.com/reference/stl/multiset/

Edit: (seems like it was unclear before) It is in general better to use a container like std::(multi)set or std:(multi)map than using std::list and sorting it afterwards everytime an element is inserted because std::list does not perform very good in inserting elements in the middle of the container.

MKroehnert
Note that for list, inserting one by one, even with a linear insertion time, is at least O(n^2). You're better off inserting them all and sorting once.
Billy ONeal
That is not true really true because you would have n-times an insertion of O(log n) so you would get O(n log n) which is the same as for sorting.
MKroehnert
@MKroehnert - lists don't allow logarithmic insertions.
Niki Yoshiuchi
The problem is that you only have `O(log n)` insertion in a randomly accessible structure. In a list you only have bidirectional traversal, and thus `O(n)` insertion even if it's sorted...
Matthieu M.
I do not propose to use std::list. In fact I was trying to state the opposite.
MKroehnert
@Niki: I was refering to std::set and not to std::list
MKroehnert
@MKroehnert - Your answer was perfectly clear, your comment was not. Billy was referring to a list when he said it would take O(n^2) time. You then replied to him that that was not true. My comment was directed at your comment to Billy, not your answer.
Niki Yoshiuchi
@Niki: sorry about that, the comment was probably unclear because the one from Billy does not really relate to my answer and is a bit confusing as far as I can see.
MKroehnert