我最近发现了boost :: multi_index_container,我对他的表现感到好奇,与我自己实现的基于多级映射的类似容器相比,定义为:
typedef int Data;
typedef uint64_t MainKey;
typedef uint64_t SecondaryKey;
typedef std::unordered_map<SecondaryKey, Data> SecondaryMap;
typedef std::unordered_map<PrimaryKey, SecondaryMap> PrimaryMap;
密钥排序并不重要。快速查找非常重要,我可以使用以下内容:
// find primaryKey=10 and secondaryKey=30
PrimaryMap m;
....
auto i1 = m.find( 10);
if ( i1 != m.end())
{
auto& secondary = i1->second;
auto i2 = secondary.find( 30);
if ( i2 != secondary.end())
{
found = true;
....
}
}
我想知道会是什么
我尝试配置模板,但我不确定这是否是最佳解决方案:
struct RecordKey
{
MainKey mainKey;
SecondaryKey secondaryKey;
RecordKey( const MainKey mainKey, SecondaryKey secondaryKey):
mainKey( mainKey),
secondaryKey( secondaryKey)
{}
};
struct Record: public RecordKey
{
Data data;
Record( const MainKey mainKey = 0, const SecondaryKey secondaryKey = 0, const Data& data = 0):
RecordKey( mainKey, secondaryKey),
data( data)
{}
};
struct MainKeyTag {};
struct SecondaryKeyTag {};
struct CompositeKeyTag {};
using boost::multi_index_container;
using namespace boost::multi_index;
typedef boost::multi_index_container<Record,
indexed_by < /*random_access<>,*/
hashed_non_unique<tag<MainKeyTag>, BOOST_MULTI_INDEX_MEMBER( RecordKey, MainKey, mainKey) >,
hashed_non_unique<tag<SecondaryKeyTag>, BOOST_MULTI_INDEX_MEMBER( RecordKey, SecondaryKey, secondaryKey) >,
hashed_unique<tag<CompositeKeyTag>, composite_key<Record, member<RecordKey, MainKey, &RecordKey::mainKey>,
member<RecordKey, SecondaryKey, &RecordKey::secondaryKey> > > > > RecordContainer;
答案 0 :(得分:8)
你可以通过选择BMI中的有序(而不是散列)索引来获得你的蛋糕并吃掉它。
有序复合索引的一个很好的属性允许您通过部分键进行查询,因此您只需要定义复合索引以便能够通过主索引进行查询:
typedef boost::multi_index_container<
Record,
indexed_by<
ordered_non_unique< tag<CompositeKeyTag>,
composite_key<Record,
member<RecordKey, MainKey, &RecordKey::mainKey>,
member<RecordKey, SecondaryKey, &RecordKey::secondaryKey>
> > > > RecordContainer;
现在您可以按mainKey
查询:
range = index.equal_range(10);
或者通过复合:
range = index.equal_range(boost::make_tuple(10,30));
背景:
这是一个完整的演示 Live On Coliru :
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
using MainKey = uint64_t;
using SecondaryKey = uint64_t;
using Data = std::string;
struct RecordKey
{
MainKey mainKey;
SecondaryKey secondaryKey;
RecordKey( const MainKey mainKey, SecondaryKey secondaryKey):
mainKey( mainKey),
secondaryKey( secondaryKey)
{}
};
struct Record: public RecordKey
{
Data data;
Record( const MainKey mainKey = 0, const SecondaryKey secondaryKey = 0, const Data& data = 0):
RecordKey( mainKey, secondaryKey),
data( data)
{}
friend std::ostream& operator<<(std::ostream& os, Record const& r) {
return os << " Record[" << r.mainKey << ", " << r.secondaryKey << ", " << r.data << "]";
}
};
struct MainKeyTag {};
struct SecondaryKeyTag {};
struct CompositeKeyTag {};
using boost::multi_index_container;
using namespace boost::multi_index;
typedef boost::multi_index_container<
Record,
indexed_by<
ordered_non_unique< tag<CompositeKeyTag>,
composite_key<Record,
member<RecordKey, MainKey, &RecordKey::mainKey>,
member<RecordKey, SecondaryKey, &RecordKey::secondaryKey>
> > > > RecordContainer;
int main()
{
RecordContainer records;
records.insert(Record(10, 20, "12"));
records.insert(Record(10, 30, "13"));
records.insert(Record(10, 30, "13 - need not be unique!"));
records.insert(Record(30, 40, "34"));
records.insert(Record(30, 50, "35"));
records.insert(Record(50, 60, "56"));
records.insert(Record(50, 70, "57"));
records.insert(Record(70, 80, "78"));
std::cout << "\nAll records:\n----------------------------------------------------------------------\n";
for (auto const& r : records)
std::cout << r << "\n";
{
std::cout << "\nAll records with (main) == (10):\n----------------------------------------------------------------------\n";
auto& index = records.get<0>();
auto range = index.equal_range(10);
for (auto const& r : boost::make_iterator_range(range.first, range.second))
std::cout << r << "\n";
}
{
std::cout << "\nAll records with (main,secondary) == (10,30):\n----------------------------------------------------------------------\n";
auto& index = records.get<0>();
auto range = index.equal_range(boost::make_tuple(10,30));
for (auto const& r : boost::make_iterator_range(range.first, range.second))
std::cout << r << "\n";
}
}
输出:
All records:
----------------------------------------------------------------------
Record[10, 20, 12]
Record[10, 30, 13]
Record[10, 30, 13 - need not be unique!]
Record[30, 40, 34]
Record[30, 50, 35]
Record[50, 60, 56]
Record[50, 70, 57]
Record[70, 80, 78]
All records with (main) == (10):
----------------------------------------------------------------------
Record[10, 20, 12]
Record[10, 30, 13]
Record[10, 30, 13 - need not be unique!]
All records with (main,secondary) == (10,30):
----------------------------------------------------------------------
Record[10, 30, 13]
Record[10, 30, 13 - need not be unique!]
答案 1 :(得分:0)
多索引容器必须有3个索引:
hashed
- 因为std::unordered_map
经过哈希处理,
non_unique
- 因为多个记录可以具有相同的密钥; hashed
- 因为std::unordered_map
经过哈希处理,unique
- 因为元组(主键,辅助键)在地图映射中是唯一的
结构容器定义为:
typedef boost::multi_index_container<Record, indexed_by <
hashed_non_unique<tag<MainKeyTag>, BOOST_MULTI_INDEX_MEMBER( RecordKey, MainKey, mainKey) >,
hashed_non_unique<tag<SecondaryKeyTag>, BOOST_MULTI_INDEX_MEMBER( RecordKey, SecondaryKey, secondaryKey) >,
hashed_unique<tag<CompositeKeyTag>,
composite_key<Record,
member<RecordKey, MainKey, &RecordKey::mainKey>,
member<RecordKey, SecondaryKey, &RecordKey::secondaryKey> > > > > RecordContainer;
插入是:
RecordContainer c;
c.insert( Record( 10, 20, 0));
c.insert( Record( 10, 30, 1));
c.insert( Record( 10, 40, 2));
查询是:
auto& index = c.get<CompositeKeyTag>();
auto pos = index.find( boost::make_tuple( 10, 30)); // don't use std::make_tuple!
if ( pos != index.end())
{
found = true;
data = pos->data;
}
答案 2 :(得分:0)
类似的情况,但是我的组中不允许使用以下方式实现提升,如果使用辅助键查找,则只需要一次查找而不是两次:
#include<map>
using namespace std;
template<class PrimaryKey, class SecondaryKey, class Data>
class MyMultiIndexedMap
{
private:
typedef map<PrimaryKey, Data*> PT;
typedef map<SecondaryKey, Data*> ST;
PT pri_data_;
ST sec_data_;
public:
bool insert(PrimaryKey pk, SecondaryKey sk, Data *data);
Data* findBySecondaryKey(SecondaryKey sk);
Data* findByPrimaryKey(PrimaryKey pk);
};