we got this map :
std::map <int, int> values;
would this function be the same as the push_back function of a Vector :
void PushBack(int value)
{
values[values.size()] = value;
}
since size returns the size of the container I thought it would be correct, according to the following scenario it is :
index 0 = 200
index 1 = 150
you want to push back 100, values.size() would return 2, right? so then, it would , just like the normal push_back go inside index 2, correct?
The whole point of maps is to lookup and store data based on a key that uniquely represents that data.
If you're doing this there's no point in using a map; you should choose another data structure that more appropriately addresses the design needs of the application.
Maps and vectors are very different.
The short version to the actual question you asked:
if all you do on your customized map is key-based lookup of already existing keys (the operator[]) and your push_back it may act like an inefficient drop-in replacement for vector where you only use the vector operator[] and push_back, yes.
The long version providing some background on why what you are doing is probably not actually what you want:
A map doesn't have an index, it has a key. A map is usually implemented as a red-black tree. Such a data structure allows for efficient lookup based on the key. You usually care about the key of a particular element, the key itself carries important information. Keys are usually not contiguous, and maps will not allocate space for keys that are not used in the map.
A vector is a contiguous block of memory. This allows for efficient indexed access. An index is not the same as a key: you generally don't care about which index a particular element gets, which index you do get depends on the order of insertion (they key is independent of the insertion order in in a map), indexes into vectors are always integer values, and you cannot have non-contiguous indexes.
If all you do in your map is your own custom push_back then to the outside it might appear to function like a vector in some contexts, and it might not in ways in other contexts (e.g. iterator invalidation).
Since you don't actually care about the key for the element that gets added in your example the choice of a map is pointless. Indexed lookup in the vector will be faster, and memory overhead will be smaller (though you could end up with memory fragmentation issues if you allocate very many objects, but that's a separate subject).
And finally, if you don't know which container class to use, vector and list are the places to start. Understand the differences between those two, and when you should use either of them, and then move on to the more advanced, specialized containers like map, set, their "multi" variants, and their "unordered" variants.
Unless you only use the map in a very special way, it won't be correct. Consider this scenario:
std::map<int, int> values;
values[1] = 42;
PushBack(7);
values now holds just one element, 7, at index 1.
The question is, of course, if you need 'push back', why use a map in the first place.
If you want push_back then consider using a std::vector. A map is an associative array, to do fast lookup by a specified type of key. They are not designed to do push_back like vector is.
Difficult to say what you want to achieve, and why you try to use map instead of vector, but better method could be:
void PushBack(int value)
{
int idx = 0;
if( values.size() ) idx = values.rbegin()->first + 1;
values[idx] = value;
}
Related
Essentially, I'd like a container in which one element can be accessed by many keys. This could be done by defining some multi-key class to be used as the map's key type, but since such a solution doesn't allow modification of the keys of elements which have already been inserted, I'm unable to make new aliases for existing entries.
I appreciate that with std::map keys need to be constant for the purposes of ordering, but why should this limitation exist with std::unordered_map?
If need be, I suppose I could just use a map of pointers, but is there a better, more elegant solution?
Edit: Thanks for clearing that up Andrei, Xeo. Nicol, any suggestions as to what container I should used?
Well, the reason why std::unordered_map does not let you modify the key is pretty much the same as the reason why other associative containers won't let you modify it: it would mess up the internal organization of that data structure.
In an unordered_map, the key is used to obtain a hash, and that hash tells the container in which bucket to place your element (and which bucket to retrieve it from, of course). If you modify the key, you modify the hash, and that means your element should be moved to a different bucket. That's like removing it and inserting it again, basically.
The whole idea of an associative container, on the other hand, is that any element is represented by one value which is fixed, so that its position in the container can be quickly computed as a function of that value. If multiple keys were allowed, which one would you use to quickly determine where the element is stored or is to be stored?
What you want is probably an ad-hoc data structure with complexity guarantees different from the ones of the Standard Library.
Personally, however, it seems to me like you are just looking for reference semantics, because you intend to share several views of one object. That would naturally lead me to the use of (smart) pointers, especially when I hear the world "alias". I suggest you to go for a map with shared_ptrs as values.
In associative containers (e.g. map, unordered_map), the value of key determines the position of the element in the data structure. In the non-multi associative containers, it is also necessary that the keys are unique.
If modifying the key were allowed, then that would jeopardize the aforementioned design invariants.
In map, placement of the element in the binary search tree
In unordered_map, linking the element to a hash bucket
If I understand OP's requirement, then it might be achieved by writing a wrapper on the container's insert(), such as the following C++-ish pseudocode:
Iterator insert_wrapper( Container & cont, Element const & elem ) {
if elem in cont {
cont.erase( elem );
}
return cont.insert( elem );
}
Would you find a map of references more tasteful than a map of pointers?
int value = 6;
std::unordered_map<int, int&> m;
for(int i=0; i<5; ++i)
m.emplace(i, value);
value = 4;
for(auto const& i: m)
std::cout<<i.second<<' ';
Of course, you have to store the actual values somewhere else, as the example has shown.
std::vector<std::string> vec1, vec2, vec3, vec4;
//populate all vectors, all have the same size
//vec1 has different values
Now given some "key" in vec1, such as "foo", how do I quickly get the corresponding strings from the other vectors?
I will have to do this many times, with different keys in vec1, so this operation has to be fast.
Should I create a map that maps the elements in vec1 into index values (0,1,2,3,4...)?
How is this best done in C++?
Depends on what you mean by "quickly".
If you care about complexity of retrieval by value, I would suggest to consider using an associative container such as std::unordered_set (constant lookup and insertion/removal time), or std::set and std::multiset (logarithmic lookup and insertion/removal time, the second one with duplicates allowed) instead of a vector.
However, it must be said that vectors allocate a contiguous region of memory to store their elements, so linear access will result in a high cache hit rate: thus, even though the complexity is worse, access is still "fast" in general, and you can use regular STL algorithms such as std::find or std::find_if() to find elements that match a given value or satisfy a given predicate.
Often, locality of the data can compensate for a worse complexity. The key here is to always do repeated measurements to determine what's the solution which gives you the best performance.
That said, the optimal solution is likely to depend on your overall workload: are you doing element-by-element iterations of your vectors at all? How often do you need to retrieve your elements by position? If those are not frequent operations, you might not need a vector. Moreover, how often are those vectors updated? How often do you need to lookup an element in those vectors by value? Your question does not say much about this.
If memory overhead is not an issue for you, you can certainly consider building a separate map as an index, and maintain redundant structures. If your vectors will be frequently updated with insertions and deletions, however, ensuring the consistency of the index and the vectors might become troublesome.
Sounds like what you really want is a std::unordered_map<std::string, std::tuple<std::string, std::string, std::string>>. This would save you having to maintain the invariant that the std::vectors must be the same length. It will also give you constant time lookup of the other strings. For example,
typedef std::tuple<std::string, std::string, std::string> value_type;
std::unordered_map<std::string, value_type> map;
// Populate the map
map["foo"] = std::make_tuple("first", "second", "third");
// ...
std::get<0>(map["foo"]); // Get the first string that "foo" maps to
If you really don't want to change the design from using four std::vectors, then you should use std::find and std::distance to find the index of "foo" in the first std::vector and then use that index on the others:
auto key_it = std::find(std::begin(vec1), std::end(vec1), "foo");
int index = std::distance(std::begin(vec1), key_it);
std::string s2 = vec2[index];
std::string s3 = vec3[index];
std::string s4 = vec4[index];
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.
I have a map (for example, of character to integer). I insert values into this map one by one. For example, here are four insertions:
1: A -> 1
2: B -> 2
3: C -> 3
4: D -> 1
I would like to sort the map keys based on their associated values. So, at each insertion, I would have the sorted output:
1: A(1)
2: B(2), A(1)
3: C(3), B(2), A(1)
4: C(3), B(2), A(1), D(1)
Furthermore, I would like to be able to overwrite existing mappings to keep the keys (characters) unique. So a fifth insertion:
5: A -> 27
Would cause the sorted output to be:
5: A(27), C(3), B(2), D(1)
One way I can do this is using a multimap. The key of the multimap would be the integer, and the values would be the characters. Each insertion into the multimap would first need to check if the character is already present in the multimap, and remove that mapping before performing the insertion. The multimap keeps the keys ordered, so that takes care of the sorting.
Is there a faster way to do this? Is there a different, more efficient container that I should be using?
EDIT
Here's the C++ STL multimap I'm using. It's handy because it keeps its elements internally ordered.
Here's a related question. I'm trying to avoid doing what's suggested in the accepted solution: creating another map.
What I would have done would be something like this. Imagine your map maps x to y. I would create a struct (class, whatever):
struct element
{
map_this_t x;
to_this_t y;
bool operator < (element &rhs)
{
return y < rhs.y; // sorted based on y
}
};
Then create a set<element> and insert into that. If you iterate over all the data in the set, you well get the data in the order you want. When inserting, first search and see if an element with x value as the one you want exists. If so, just update the y, otherwise insert a new element.
Generally a map is a shuffled data structure (at least for the associated values).
So, sorting elements of a map is meaningless.
Therefore you should use something like list or array to keep elements sorted.
I think the best solution for your issue is the simplest way: Store the elements in a list and sort it. Or you can use heaps.
UPDATE:
Maps are a kind of associative container that stores elements formed
by the combination of a key value and a mapped value.
In a map, the key value is generally used to uniquely identify the
element, while the mapped value is some sort of value associated to
this key. Types of key and mapped value may differ. For example, a
typical example of a map is a telephone guide where the name is the
key and the telephone number is the mapped value.
Internally, the elements in the map are sorted from lower to higher
key value following a specific strict weak ordering criterion set on
construction.
As associative containers, they are especially designed to be
efficient accessing its elements by their key (unlike sequence
containers, which are more efficient accessing elements by their
relative or absolute position) [1].
[1] http://www.cplusplus.com/reference/stl/map/
A map is sorted by it's keys, by definition.
The values cannot be used in the ordering predicate for a map, because the values are non-const! Changing them would invalidate the container invariants (ordering).
If you want the entries ordered by 'value', it is implicitely a key, and you likely require a
std::set<std::pair<key, value> >
Update Here is a working demo of that: https://ideone.com/SgbEN
instead. To be able to re-order by a different predicate in place, you'd need a list, vector or any other sequential container.
Edit
The list solution is far too inefficient, since I would have to sort after each insertion, and wouldn't have an effective way of keeping the keys unique.
The solution here is to use the
std::make_heap
std::push_heap
and std::sort_heap
algorithms. They work well with lists (as well as vectors for cheap value_types - or using c++0x move semantics)
If you cannot afford the sort_heap step before using the list as ordered: use
insert_point = std::lower_bound(lst.begin(), lst.end(), insertee);
st.insert(insertion_point, insertee);
to insert directly in ordered position. You can expect push_heap to be faster for many insertions, and lowerbound/insert to be faster for many accesses
just use a map <char,int> and your keys will remain unique an pairs of <char,int> will store sorted in it.
to sort the elements based on their associated values store pair<int,char> in a set too.
I need some sort of dynamic array in C++ where each element have their own id represented by an int.
The datatype needs these functions:
int Insert() - return ID
Delete(int ID)
Get(ID) - return Element
What datatype should I use? I'we looked at Vector and List, but can't seem to find any sort of ID. Also I'we looked at map and hastable, these may be usefull. I'm however not sure what to chose.
I would probably use a vector and free id list to handle deletions, then the index is the id. This is really fast to insert and get and fairly easy to manage (the only trick is the free list for deleted items).
Otherwise you probably want to use a map and just keep track of the lowest unused id and assign it upon insertion.
A std::map could work for you, which allows to associate a key to a value. The key would be your ID, but you should provide it yourself when adding an element to the map.
An hash table is a sort of basic mechanism that can be used to implement an unordered map. It corresponds to std::unordered_map.
It seems that the best container to use is unordered_map.
It is based on hash. You can insert, delete or searche for elements in O(n).
Currently unordered_map is not in STL. If you want to use STL container use std::map.
It is based on tree. Inserts, deletes and searches for elements in O(n*log(n)).
Still the container choice depends much on the usage intensity. For example, if you will find for elements rare, vector and list could be ok. These containers do not have find method, but <algorithm> library include it.
A vector gives constant-time random access, the "id" can simply be the offset (index) into the vector. A deque is similar, but doesn't store all items contiguously.
Either of these would be appropriate, if the ID values can start at 0 (or a known offset from 0 and increment monotonically). Over time if there are a large amount of removals, either vector or deque can become sparsely populated, which may be detrimental.
std::map doesn't have the problem of becoming sparsely populated, but look ups move from constant time to logarithmic time, which could impact performance.
boost::unordered_map may be the best yet, as the best case scenario as a hash table will likely have the best overall performance characteristics given the question. However, usage of the boost library may be necessary -- but there are also unordered container types in std::tr1 if available in your STL implementation.