I want to use a std::multimap container, but I need to know that it will always maintain order, as in the first element in will be the first element iterated over and the second will always be the second.
What I'm asking is this:
Is std::multimap< key, value > equivalent to std::vector< std::pair< const key, std::vector< value > > >
A multimap is not the equivalent of a vector, not in terms of implementation. Multimaps are usually implemented as a binary search tree. The elements of a multimap are always kept in a sorted order by their key following a strict weak order criteria indicated by the comparison object.
Thus, when you iterate over the elements of a multimap their order is the sorted order provided by the comparison object.
Is std::multimap< key, value > equivalent to std::vector< std::pair<
const key, std::vector< value > > > ?
No, these are two different containers and they exhibit many differences in how they store underlying data, how they manage the memory, how you can access this data and in order the data is stored. In vector the data is stored in order that you have push_back ed it, but in multimap data is always sorted, so e.g. the last value you have inserted into multimap may be actually accessed with multimap.begin() or multimap.begin() + 10.
You can have an integer key in multimap and insert with incremented key to force order of sort be same as order of insertion.
Although they are not the same in terms of implementation, your question indicates that you're really just concerned about the ordering. I found the following information related to the ordering:
Multimaps are associative containers that store elements formed by a
combination of a key value and a mapped value, following a specific
order, and where multiple elements can have equivalent keys.
Internally, the elements in a multimap are always sorted by its key
following a specific strict weak ordering criterion indicated by its
internal comparison object (of type Compare).
Source, cplusplus.com
A std::vector< std::pair< const key, std::vector< value > > > allows you to have any ordering of the key elements, whereas a std::multimap<key, value> doesn't.
From cppreference:
Multimap is an associative container that contains a sorted list of key-value pairs, while permitting multiple entries with the same key. Sorting is done according to the comparison function Compare, applied to the keys.
It sounds like you are asking what is the order among equivalent entries.
The order of the key-value pairs whose keys compare equivalent is the order of insertion and does not change. (since C++11)
You can keep a vector in the same order as what a multimap provides, by making sure that you insert new entries after all the existing equivalent entries, but before any entries who's keys are later in the order. A simple way would to gate all insertion through
vec.insert(std::upper_bound(vec.begin(), vec.end(), to_insert, key_compare), to_insert);
Related
As it makes sense, lower_bound and upper_bound are absent for std::unordered_map because there is no order for elements.
However std::unordered_map has method equal_range. it return iterators for range corresponding to a key.
How does it make sense? Since there can be only one element with a key in std::unordered_map. It is just find method.
Also, in std::unordered_multimap, does it presence means all elements with same key will always come together while iterating unordered_multimap with a iterator?
How does it make sense?
It kind of does. The standard requires all associative container to offer equal_range so the non multi containers need to provide it. It does make writing generic code easier so I suspect that is the reason why all of the containers are required to use it.
Does it presence means all elements with same key will always come together while iterating unordered_map with a iterator?
Actually, yes. Since the all of the keys will have the same value they will hash to the same value which means they all get stored in the same bucket and will be grouped together since the keys compare equally. From [unord.req]/6
An unordered associative container supports unique keys if it may contain at most one element for each key. Otherwise, it supports equivalent keys. unordered_set and unordered_map support unique keys. unordered_multiset and unordered_multimap support equivalent keys. In containers that support equivalent keys, elements with equivalent keys are adjacent to each other in the iteration order of the container. Thus, although the absolute order of elements in an unordered container is not specified, its elements are grouped into equivalent-key groups such that all elements of each group have equivalent keys. Mutating operations on unordered containers shall preserve the relative order of elements within each equivalent-key group unless otherwise specified.
emphasis mine
It's for consistency with the other containers.
It makes more sense in the _multi variants, but is present in all the associative (and unordered associative) containers in the standard library.
It allows you to write code like
template <typename MapLike, typename KeyLike>
void do_stuff(const MapLike & map, const KeyLike & key)
{
auto range = map.equal_range(key);
for (auto it = range.first; it != range.second; ++it)
// blah
}
Which does not care about what specific container it is dealing with
cplusplus.com writes about std::unordered_map::equal_range:
Returns the bounds of a range that includes all the elements in the container with a key that compares equal to k. In unordered_map containers, where keys are unique, the range will include one element at most.
Also, in std::unordered_multimap, does it presence means all elements with same key will always come together while iterating unordered_multimap with a iterator?
In general, the order, in which elements stored in a std::unordered_multimap are obtained while traversing it, is actually not defined. However, note that std::unordered_multimaps are usually implemented as hash tables. By analysing such an implementation you will realize that the ordering is not going to be as "undefined" as someone might initially think.
At element insertion (or hash table rehashing), the value resulting of applying the hash function to an element's key is used to select the bucket where that element is going to be stored. Two elements with equal keys will result in the same hash value, therefore they will be stored in the same bucket, so they come togetherX while iterating an std::unordered_multimap.
XNote that even two elements with different keys might also result in the same hash value (i.e., a collision). However, std::unordered_multimap can handle these cases by comparing the keys against equality, and therefore still group elements with equal keys together.
Is there any container available in C++ STL to store unsorted key value pair with duplicate keys?
I was thinking std::unordered_multimap container will help me in this case but the elements with equivalent keys are grouped together in this.
I would recommend you to look at sequence containers. Basically you can store std::pair< key, value > at some sequence container.
If you just need to store key-value pairs and sometimes add new key-value pair at the end of the container then std::vector is enough. If you additionally want to insert elements in the beginning of the container then look at std::deque. And so on...
So the best strategy is to analyze your constraints and choose the appropriate sequence container.
I have a multimap containing over 5 million pairs and I need to swap the keys with the values.
unordered_multimap<int, int> edge;
Due to the large size of the container and the processes involved, I would prefer to not have to create a new multimap with the swapped pairs by iterating over each element of the map.
What would be the best way, if any, to do this in place?
The proper approach is not to do this at all, but instead to have a bi-directional map in the first place, on which you can perform lookup in either direction.
Consider looking into Boost.Bimap.
You can not do this in-place.
The map you have stored the elements based of the hash values of its key. If you want to hash on a different key (the former value) you have to rebuild the whole map or think of a different way to store the elements.
Boost.Bimap (as suggested by Lightness Races in Orbit) for example supports bidirectional unordered multimaps.
I need to implement a key-value data structure that search for a unique key in O(lgn) or O(1) AND get max value in O(1). I am thinking about
boost::bimap< unordered_set_of<key> ,multiset_of<value> >
Note that there is no duplicated key in my key-value data sets. However, two keys may have the same value. Therefore I used multiset to store values.
I need to insert/remove/update key-value pair frequently
How does it sounds ?
It depends on what you want to do. So it is clear that you want to use it for some get-the-maximum-values-in-an-iteration construction.
Question 1: Do you access the elements by their keys as well?
If yes, I can think of two solutions for you:
use boost::bimap - easy, tested solution with logarithmic runtimes.
create a custom container that contains an std::map (or for even faster by key access std::unordered_map) and a heap implementation (e.g. std::priority_queue<std::map<key, value>::iterator> + custom comparator) as well, keeps them in sync, etc. This is the hard way, but maybe faster. Most operations on both will be O(logn) (insert, get&pop max, get by key, remove) but the constant sometimes do matter. Although is you use std::unordered_map the access by key operation will be O(1).
You may want to write tests for the new container as well and optimize it for the operation you use the most.
If no, you really just access using elements using the maximum value
Question 2: do you insert/remove/update elements randomly or you first put in all elements in one round and then remove them one by one?
for random insert/remove/updates use std::priority_queue<std::pair<value, key>>
if you put in the elements first, and then remove them one-by-one, use and std::vector<std::pair<value, key>> and std::sort() it before the first remove operation. Do not actually remove the elements, just iterate on them.
You could build this using a std::map and a std::set.
One map to hold the actual values, i.e. std::map<key, value> m;. This is where your values are stored. Inserting elements into a map is O(log n).
A set of iterators pointing into the map; this set is sorted by the value of the respective map entry, i.e. std::set<std::map<key, value>::iterator, CompareBySecondField> s; with something like (untested):
template <class It>
struct CompareBySecondField : std::binary_function<It, It, bool> {
bool operator() ( const T &lhs, const T &rhs ) const {
return lhs->second > rhs->second;
}
};
You can then get an iterator to the map entry with the largest value using *s.begin();.
This is rather easy to build, but you have to make sure to update both containers whenever you add/remove elements.
Since maps dont allow duplicate values . Are there any other containers that are part of C++ standard library that allow duplicates that store values by key value pair?
You can use std::multimap
Multimap is a Sorted Associative Container that associates objects of type Key with objects of type Data. multimap is a Pair Associative Container, meaning that its value type is pair. It is also a Multiple Associative Container, meaning that there is no limit on the number of elements with the same key.