I need a data structure that can hold one to many relationship.
Some thing like a student can attend many courses. only thing is i might have it in order of thousands. one key to multiple values.
map<char,int> mymap; wont allow to insert same key again.
You can use std::multimap for this.
I would suggest this:
std::map<Student, std::vector<Course>> StudentInfos;
You just could use student id as key for faster comparison, or you could compare only id in operator< when comparing two instances of Student.
Use std::multimap<Key, T> and std::multimap<Key, T>::equal_range if it's okay to duplicate the key a lot. This is probably okay for integers and such.
If you want your key only once, as you will probably want for slightly more complex keys, such as std::string, use std::map<Key, std::vector<T>> and its find method.
The nested container is more appropriate for your example. The multimap is really only more appropriate if you have different keys that only "seem" identical respective your predicate.
Related
I want to make a map like structure to allow searching by two keys both will be strings, here's an example:
Myclass s;
Person p = s.find("David"); // searching by name
// OR
p = s.find("XXXXX"); // searching by ID
i don't want a code solution, i just want some help to get started like the structures i can use to achieve what i want, help is appreciated guys, it's finals week.
Put your records into a vector (or list). Add a pointer to the record objects to two maps, one with one key and one with the other.
There are many different ways how this could be achieved. The question is: what are the complexities of insert, delete and lookup operations that you aim for?
std::map is implemented as red-black tree that provides increadibly quick self-balancing (rotations) and all of mentioned operations (lookup/find, insert, delete) with complexity of O(log(n)). Note that this suits the idea of single key.
With 2 keys you can not keep elements sorted because the order based on one key will be most likely different than order based on the other one. The most straightforward and natural approach would be storing records in one container and holding the keys used by this container in 2 different structures, one optimized for retrieving this key given id and the other one for retrieving it given name.
If there is a constraint of storing everything at one place while you'd like to optimize find operation that will support two different keys, then you could create a wrapper of std::map<std::string, Person> where each element would be contained twice (each time under a different key), i.e. something like:
std::map<std::string, Person> myContainer;
...
Person p;
std::string id = "1E57A";
std::string name = "David";
myContainer[id] = p;
myContainer[name] = p;
I can think of 2 advantages of doing this:
quite satisfying performance:
lookup with complexity O(log(2*n))
insertion & deletion with complexity O(2*log(2*n))
extremely simple implementation (using existing container)
you just need to remember than the "expected" size of the container is half of its actual size
both of the keys: id and name should be attributes of Person so that when you find a concrete element given one of these keys, you immediately have the other one too
Disadvantage is that it will consume 2x so much memory and there might even be a constraint that:
none of the names should be an id of some other person at the same time and vice versa (no id should be a name of some other person)
I am looking for something like a school time table. Based on two input - Day of the week and Time of the day, one decides the subject. To implement this in c++, I was thinking of something like "map < pair < int, int>, int>".
I was reading here to use a key class and operator overloading.
Is there any other elegant way of doing it?
Thanks in Advance
That's not a map with two keys (which would allow you to look up items from knowledge of just one key), it's a composite key, and map<pair<day, time>, subject> should work just fine.
Also consider map<day, map<time, subject>>.
You could typedef it.
typedef pair<int, int> key;
map<key, int> myMap = new map<key, int>();
You can't create a map with 2 key values, you can create a map with a complex key value (composed of two types). However, this won't let you look at the map for say just day of week regardless of time of day. I would create a new class to use as key, and some helper functions to be able to work by just day or just time.
Also, for your use case Boost.MultiIndex may help you.
I need to insert values into std::map (or it's equivalent) to any free position and then get it's key (to remove/modify later). Something like:
std::map<int, std::string> myMap;
const int key = myMap.insert("hello");
Is it possibly to do so with std::map or is there some appropriate container for that?
Thank you.
In addition to using a set, you can keep a list of allocated (or free)
keys, and find a new key before inserting. For a map indexed by
int, you can simply take the last element, and increment its key. But
I rather think I'd go with a simple std::vector; if deletion isn't
supported, you can do something simple like:
int key = myVector.size();
myVector.push_back( newEntry );
If you need to support deletions, then using a vector of some sort of
"maybe" type (boost::optional, etc.—you probably already have
one in your toolbox, maybe under the name of Fallible or Maybe) might be
appropriate. Depending on use patterns (number of deletions compared to
total entries, etc.), you may want to search the vector in order to
reuse entries. If your really ambitious, you could keep a bitmap of the
free entries, setting a bit each time you delete and entry, and
resetting it whenever you reuse the space.
You can add object to an std::set, and then later put the whole set into a map. But no, you can't put a value into a map without a key.
The closest thing to what you're trying to do is probably
myMap[myMap.size()] = "some string";
The only advantage this has over std::set is that you can pass the integer indexes around to other modules without them needing to know the type of std::set<Foo>::iterator or similar.
It is impossible. Such an operation would require intricate knowledge of the key type to know which keys are available. For example, std::map would have to increment int values for int maps or append to strings for string maps.
You could use a std::set and drop keying altogether.
If you want to achieve something similar to automatically generated primary keys in SQL databases than you can maintain a counter and use it to generate a unique key. But perhaps std::set is what you really need.
What should i use between QMap::insertMulti and QMultiMap to handle :
2 -> abc
2 -> def
3 -> ghi
3 -> jkl
What's the difference enter the 2 solutions ?
Reading Container Classes:
QMap<Key, T>
This provides a dictionary (associative array) that maps keys of type Key to values of type T. Normally each key is associated with a single value. QMap stores its data in Key order; if order doesn't matter QHash is a faster alternative.
QMultiMap<Key, T>
This is a convenience subclass of QMap that provides a nice interface for multi-valued maps, i.e. maps where one key can be associated with multiple values.
it looks like both can do the job. In this document there is also Algorithmic Complexity section where you can see that both classes have the same complexity.
I would choose QMultiMap just to better document the fact I'm going to hold multiple values with the same key.
Both can serve this purpose. QMultiMap is actually a subclass of QMap.
If you are willing to have multiple values for single key, you can use:
QMap : for inserting use insertMulti
QMultiMap : for inserting use insert
If you are willing to have single value for single key, you can use:
QMap : for inserting use insert
QMultiMap : for inserting use replace
You can see that both can server both purpose. But, each have unique default behavior which matches its name. Also, each have some methods or operators which is convenient for single/multi.
It is better to choose type depending on your need. It is a good practice. For example, if you use QMap for storing single key multiple values, some other person who is going through your class members might get the impression that you are willing to save single key value pairs (from the data type)
Similarly, if you use QMultiMap, anyone reading the definition can get the idea that the data will have multiple value for same key.
I need to use multiple keys(int type) to store and retrieve a single value from a hash table. I would use multiple key to index a single item. I need fast insertion and look up for the hash table. By the way, I am not allowed to use the Boost library in the implementation.
How could I do that?
If you mean that two ints form a single key then unordered_map<std::pair<int,int>, value_type>. If you want to index the same set of data by multiple keys then look at Boost.MultiIndex.
If the key to your container is comprised of the combination of multiple ints, you could use boost::tuple as your key, to encapsulate the ints without more work on your part. This holds provided your count of key int subcomponents is fixed.
Easiest way is probably to keep a map of pointers/indexes to the elements in a list.
A few more details are needed here though, do you need to support deletion? how are the elements setup? Can you use boost::shared pointers? (rather helpful if you need to support deletion)
I'm assuming that the value object in this case is large, or there is some other reason you can't simply duplicate values in a regular map.
If its always going to be a combination for retrieval.
Then its better to form a single compound key using multiple keys.
You can do this either
Storing the key as a concatenated string of ints like
(int1,int2,int3) => data
Using a higher data type like uint64_t where in u can add individual values to form a key
// Refer comment below for the approach