c++ efficient data structure for bidirectional random access - c++

I have elements a and b of two sets A and B. Now these are related to each other (0..1:n cardinality) so each a has at most one partner in B and each b can have several (at least one) associations to items in A.
A is a set of integer pairs and B are integers.
Is there efficient way to store such a "bi-directional" map?
A simple approach would be to use two maps:
map<pair<unsigned int, unsigned int>, unsigned int> AtoB
map<unsigned int, vector<pair<unsigned int, unsigned int> > > BtoA
But perhaps there is good way to deal with this more efficiently.
Thanks for your help

Boost contains two libraries to deal with this: Boost.Bimap and Boost.MultiIndex. The former is specific to the problem of bijective ("bidirectional") maps, while the second is more general and implements something akin to an in-memory database with arbitrary indexes.
Given that your unsigned int keys don't uniquely map to your pairs, I think MultiIndex is more in order. It's a long time since I've last used this library, but looking at the tutorial, you would need something like
struct YourData {
unsigned key;
std::pair<unsigned, unsigned> value;
};
typedef multi_index_container<
YourData,
indexed_by<
ordered_non_unique<member<YourData, unsigned, &YourData::key> >,
ordered_unique<member<YourData, std::pair<unsigned, unsigned>,
&YourData::value> >
>
> YourContainer;
If you don't want to use Boost, then you can at least simplify your current setup by replacing the
map<unsigned int, vector<pair<unsigned int, unsigned int> > >
by an std::multimap<unsigned, std::pair<unsigned, unsigned>>.

How about boost::bimap? http://www.boost.org/doc/libs/1_47_0/libs/bimap/doc/html/index.html I think it's for you.

Map and Multimap haves an efficiency of O(log n), so, I think is the best way to store your data. I suggest to use
map<pair<unsigned int, unsigned int>, unsigned int> AtoB
multimap<pair<unsigned int, unsigned int>, unsigned int> BtoA

Related

Boost::multi_index_container with disparate key and element types

Is it possible to use different type data structures for keys and elements in a boost::multi_index_container? GCC lets me compile something like this:
struct StructA {
std::string name;
};
struct StructB {
int primary;
int secondary;
};
using mic =
multi_index_container<
StructA,
indexed_by<
composite_key<
StructB,
member< StructB, int, StructB::primary >,
member< StructB, int, StructB::secondary >
>>>;
First, I'm not sure if the above code violates any sort of multi_index_container usage. It certainly compiles with different element (StructA) and composite index key (StructB). Second, how do I insert/emplace into such a container? Third, how do I access elements in such a container?
How do you think this is supposed to work?

Hash for a std::pair, for use in an unordered_map

When doing
unordered_map<pair<unsigned int, unsigned int>, unsigned int> m;
we get
Error C2338: The C++ Standard doesn't provide a hash for this type.
Is there a built-in way to define a hash for a std::pair of int or do we need to define it manually? (in this case, the hash could be just (the bytes of first item)(the bytes of second item of the pair) glued together).
Note: I'm using VC++ 2013.
Note2: the answer to pair<int,int> pair as key of unordered_map issue doesn't clearly address the question of how to actually create the hash with two ints, as detailed here.
If you don't want to use boost, rolling your own shouldn't be too hard.
static_assert added to ensure the assumption that 2 ints fit into 1 size_t is maintained.
using IntPair = std::pair<int, int>;
struct IntPairHash {
static_assert(sizeof(int) * 2 == sizeof(size_t));
size_t operator()(IntPair p) const noexcept {
return size_t(p.first) << 32 | p.second;
}
};
std::unordered_map<IntPair, int, IntPairHash> myMap;

Use find() on map of struct, get "has no member named XXX"

I defined a structure an use unsigned long long int as key to store structures in the map.
I have another function which finds the structs in the map and do some modification to the structs.
But I got error like this:
‘struct std::_Rb_tree_iterator<std::pair<const long long unsigned int, sStatics> >’ has no member named Latency
Can anyone tell me what is the error comes from?
The following is my code structure:
A.h:
#include <map>
struct sStatics;
extern std::map<unsigned long long int, sStatics> wsmStaticsMap;
A.cpp:
#include <map>
std::map<unsigned long long int, sStatics> wsmStaticsMap;
struct sStatics
{
std::string atcs;
uint32_t Latency;
std::vector<unsigned long int> lostWSM;
unsigned long int wrongOrderCount;
};
static void function_statics(){
std::map<unsigned long long int,sStatics>::iterator it;
it = wsmStaticsMap.find(atcs);
if (it != wsmStaticsMap.end()){
it->Latency++;
}
}
You have to write (it->second).Latency. It returns a key-value pair. You need to first select the value then an attribute within it.
You can check the reference
std::map::find returns
Iterator to an element with key equivalent to key. If no such element is found, past-the-end (see end()) iterator is returned.
It is a std::pair<Key, Value>, you need to use ->second to access the value.
Change
it->Latency++;
to
(it->second).Latency++;
Also, use auto to simplify
auto it = wsmStaticsMap.find(atcs);

I need help choosing the right c++ container

key is :(x,y) , that means 2 integers.
value is: 0 or 1.
And I have frequently operation of iteration of this hash map.
Which data structure is fit? I am using C++ stl or tr1. Don't consider boost.
Well, the data format stored obviously is a bool.
And for the key format, if you would know the bitsize of those integers and performance is a must, I would use a associative array (called a map in C++) with twice the bitwidth integers as key:
bool val = true;
uint32 x, y; // key
uint64 combo = x << 32 + y;
std::map<uint64, bool> container;
But this would work fine too and is semantically much better:
std::map<std::pair<int, int>, bool> container.
map< pair< int, int >, bool > cont;
I suggest the use of a proper hashmap (unlike std::map which isn't a hashmap):
typedef std::tr1::unordered_map<pair<int, int>, bool> MyContainer;
MyContainer m_myContainer;
I would use a std::hash_map or std::map.
I'm not sure which would give you faster performance though.

C++ - how to create a multimap with 4 variables and 4 keys

I want to create a class like below
class enumClass
{
int msdnEnum;
std::string msdnEnumString;
int localEnum;
std::string localEnumString;
}
std::set<enumClass_Objects> enums; // all msdnEnums are unique, same aplies to other three.
enums.find(given_msdnEnum)->FourthVariable;
enums.find(given_localEnum)->FirstVariable;
enums.find(given_msdnEnumStr)->anyVariable;
enums.find(given_localEnumStr)->anyVariable;
I referred boost::multiIndex. But I don't think that it helps on this case. Can anybody say the way to achieve this?
EDIT
I am not that much good in reading template classes. As for as I am concerning I didn't find any "find" methods in multiIndex. I saw only sorting out things in that example(the first basic example:link). Suggestions&advices are always welcomed
boost multiindex is exactly what you need in this case. Construct four indexes for the four keys - I guess given you guarantee that they will all be unique, make them unique indexes (I believe only one of them can be hashed_unique, but I think you can make the other three ordered_unique), and then do your searches on the each index depending on what you are searching by.
Here's a simple example using boost.multi_index:
#include <string>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
struct enumClass
{
int msdnEnum;
std::string msdnEnumString;
int localEnum;
std::string localEnumString;
};
namespace bmi = boost::multi_index;
typedef bmi::multi_index_container<
enumClass,
bmi::indexed_by<
bmi::ordered_unique<bmi::member<enumClass, int, &enumClass::msdnEnum> >,
bmi::ordered_unique<bmi::member<enumClass, std::string, &enumClass::msdnEnumString> >,
bmi::ordered_unique<bmi::member<enumClass, int, &enumClass::localEnum> >,
bmi::ordered_unique<bmi::member<enumClass, std::string, &enumClass::localEnumString> >
>
> enumClassSet;
int main()
{
enumClassSet enums;
enums.get<0>().find(/*given_msdnEnum*/); // index 0 is enumClass::msdnEnum
enums.get<1>().find(/*given_msdnEnumStr*/); // index 1 is enumClass::msdnEnumString
enums.get<2>().find(/*given_localEnum*/); // index 2 is enumClass::localEnum
enums.get<3>().find(/*given_localEnumStr*/); // index 3 is enumClass::localEnumString
}
Tag classes could be used to access the indices by name rather than ordinal index as well, usage of which would look like this:
struct byMsdnEnum;
struct byMsdnEnumStr;
struct byLocalEnum;
struct byLocalEnumStr;
typedef bmi::multi_index_container<
enumClass,
bmi::indexed_by<
bmi::ordered_unique<bmi::tag<byMsdnEnum>, bmi::member<enumClass, int, &enumClass::msdnEnum> >,
bmi::ordered_unique<bmi::tag<byMsdnEnumStr>, bmi::member<enumClass, std::string, &enumClass::msdnEnumString> >,
bmi::ordered_unique<bmi::tag<byLocalEnum>, bmi::member<enumClass, int, &enumClass::localEnum> >,
bmi::ordered_unique<bmi::tag<byLocalEnumStr>, bmi::member<enumClass, std::string, &enumClass::localEnumString> >
>
> enumClassSet;
int main()
{
enumClassSet enums;
enums.get<byMsdnEnum>().find(/*given_msdnEnum*/);
enums.get<byMsdnEnumStr>().find(/*given_msdnEnumStr*/);
enums.get<byLocalEnum>().find(/*given_localEnum*/);
enums.get<byLocalEnumStr>().find(/*given_localEnumString*/);
}
The difference between the two approaches is purely aesthetic, and of course the tag classes could be named whatever you want rather than byMsdnEnum, etc. Also note that hashed indices could be used rather than ordered indices, which would give your indices the behavior of std::unordered_map rather than std::map.
Is there a reason why you cannot use 2 maps? ( std::map< int, std::string> ). If you need to find both of the string variables by any of those two keys, then you could solve it by having a map that would pair for example msdnEnum with both strings and then have a map that would pair localEnum with msdnEnum. Than any lookup via msdnEnum would be done directly and a lookup via localEnum would first do a translation to msdnEnum and then do a direct lookup.