views:

246

answers:

8

I have the following scenario.The implementation is required for a real time application.

1)I need to store at max 20 entries in a container(STL Map, STL List etc). 2)If a new entry comes and 20 entries are already present i have to overwrite the oldest entry with the new entry.

Considering point 2, i feel if the container is full (Max 20 entries) 'list' is the best bet as i can always remove the first entry in the list and add the new one at last (push_back). However, search won't be as efficient.

For only 20 entries, does it really make a big difference in terms of searching efficiency if i use a list in place of a map?

Also considering the cost of insertion in map i feel i should go for a list?

Could you please tell what is a better bet for me ?

+1  A: 

You just need to implement a priority queue. STL Map doesn't work.

sza
http://www.cplusplus.com/reference/stl/priority_queue/
Travis Gockel
Could you please elaborate a bit ..?
Abhijeet
A priority queue doesn't store the order of insertion. I can't quite see how you would remove the *oldest* item from the heap. (Neither do I see how `std::priority_queue` helps with searching for any item.)
UncleBens
A: 

You need a Priority Queue implemented on an array. See the Binary Heap for an implementation.

fabrizioM
A: 

Do you already know that this is a bottleneck?

My advice would be to first use what is more natural to read while programming and only optimize it when you see that the performance is not what you need.

dafmetal
+2  A: 

Maintain order of insertion, or allow fast searching: choose one.

std::map is not an option here because it doesn't maintain the order of insertion. Besides, it's an associative container. You should choose between a list, a deque and a vector. In terms of performance your best bet is a list, since you can pop off an element from the back and insert a new one at the front (or vice-versa) without any shifting or performance penalty.

The cost of insertion in a map, just as a sidenote, isn't expensive it all: it's in the order of O(log n). Practically irrelevant in the case of 20 elements. The same holds for a std::set.

wilhelmtell
`list` does have the memory allocation overhead. A `deque` is probably most suitable for those operations. - However, should it be needed, one probably could overwrite the first value and relink it to the end of the list.
UncleBens
+1 for mentioning the important fact that `std::map` doesn't even meet the requirements.
Michael Burr
@UncleBens: You can use a second list to splice the nodes in and out in constant time to prevent the allocations. I'd probably still use a deque though.
Mark B
+1  A: 

With only 20 elements, I would not worry much about which container you use. If you determine that the container chosen is in fact a detriment to the performance of your application, it should be relatively easy to swap out the container chosen and replace it with a more-efficient container later.

With that being said, for a large number of elements, the std::deque would probably give you the best all-around efficiency for what you are trying to accomplish. Unlike std::vector, std::deque allows for removal from the front without needing to move all of the other elements. Unlike std::list, std::deque allows for random access of its elements.

Matthew T. Staebler
+8  A: 
1)I need to store at max 20 entries in a container(STL Map, STL List etc). 2)If a new entry comes and 20 entries are already present i have to overwrite the oldest entry with the new entry.

This seems to me the job for boost::circular_buffer.

In general the term circular buffer refers to an area in memory which is used to store incoming data. When the buffer is filled, new data is written starting at the beginning of the buffer and overwriting the old.

The circular_buffer is a STL compliant container. It is a kind of sequence similar to std::list or std::deque. It supports random access iterators, constant time insert and erase operations at the beginning or the end of the buffer and interoperability with std algorithms. The circular_buffer is especially designed to provide fixed capacity storage. When its capacity is exhausted, newly inserted elements will cause elements either at the beginning or end of the buffer (depending on what insert operation is used) to be overwritten.

The circular_buffer only allocates memory when created, when the capacity is adjusted explicitly, or as necessary to accommodate resizing or assign operations. On the other hand, there is also a circular_buffer_space_optimized available. It is an adaptor of the circular_buffer which does not allocate memory at once when created, rather it allocates memory as needed.

For the fast search, I think that with just 20 elements (if their comparison isn't too complicated) you're ok with a "low-cost" container like this and normal linear search, in my opinion it would be difficult to achieve better performance with other STL containers.

Matteo Italia
Code reuse at its best :)
Matthieu M.
If Boost is undesirable, `std::deque` with `reserve` is a close analogue.
Potatoswatter
A: 

My suggestion would be to make a circular buffer. But that only works if "old" is determined by when it was inserted, and not some field.

If you need to have a proper LRU, then you should probably go and look at something like http://www.codeproject.com/KB/recipes/LRUCache.aspx?fid=1000025&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=15

But with 20 entries as your max, it will be very hard to you to find a complex algorithm that is actually faster than the trivial lineary check of every element.

Cine
A: 

It depends on the size of the elements.

I know from my own experience that for five integers an unordered array of integers searched with linear search is faster than a set, a list or insertion sort and binary search on an ordered array.

The O() notation of an unordered array may be much worse than any of the other options but the normally unseen C in O(N+C) + C is so much smaller.

A list, set or map (anything that uses dynamic memory and is linked by pointers) will be dominated by cache misses, memory allocations and indirect reference penalties.

Zan Lynx