boost的bimap相当于STL的map的升级版本, 具有双向映射. 学过STL的map的童鞋很容易掌握它的使用.
不过, 差别肯定是有的. 因为它是双向的, 所以有左右之分. 如:
boost::bimap<int,int> bm;
bm.left就相当于STL的map, bm.right就是把STL中的key-value键值对反过来, 变成value-key, 它相应的
first和second也就变成了value和key.
举例说明, 假我们要做一个电话簿, 有区号-城市的对应关系, 有时候我们有区号, 想得到城市, 或是有城市
想得到区号, 我们可能需要这样一个双向映射关系的电话簿, 我们可以这样:
2 typedef bm_type::value_type position;
3 bm_type bmPhone;
4 bmPhone.insert( position( "0771", "南宁" ) );
5
这样, bmPhone里就插入了一个 "0771"-"南宁"的项.( 鄙人是广西人, 偏爱广西, 各位不要介意哈 ).
这里要注意的是, 在插入的时候, 使用的是 bm_type::value_type, 而不是STL的make_pair, 这一点是值
得注意的. 另一点就是, 如果插入 position( "0772", "南宁" )是会失败的, 会产生一个编译错误( 这可比
运行时失败要好得多辣 ), 因为bimap也是一个map, 不允许有重复键, 因为它是双向的, 右边的value也是
一个键值, 所以插入两个"南宁"是会失败的. 可能您会说, STL有multimap支持复制值的啊, bimap也是支持
的, 我们待会儿再说.
假设我们要通过一个区号去查找城市, 如有接口: std::string GetCityByCode( std::string strCode ); 那么我们
可以实现如下:
2 {
3 bm_type::left_const_iterator it; // 也可以使用 const_iterator
4 it = bmPhone.left.find( strCode ); // 注意有个 .left
5 if ( it != bmPhone.left.end( ) ) // 注意是 .left.end( )
6 return it->second;
7 return "";
8 }
如果我们要通过城市查区号, 那就把left换成right就成了.
贴出完整源代码:
//
#include "stdafx.h"
#include <iostream>
#include <boost/bimap.hpp>
class PhoneManager {
public:
PhoneManager( void ) { Init( ); }
void Init( void );
void ListAll( void ) const;
std::string GetCityByAreacode( std::string strAreacode ) const;
std::string GetAreacodeByCity( std::string strCity ) const;
private:
typedef boost::bimap<std::string,std::string> bm_type;
typedef bm_type::left_const_iterator left_const_iterator;
typedef bm_type::right_const_iterator right_const_iterator;
bm_type _bmValues;
};
int _tmain(int argc, _TCHAR* argv[])
{
PhoneManager pm;
pm.ListAll( );
std::cout << "=========================Test=Result===============================\n";
std::cout << "find 南宁" << "\n result is:" << pm.GetAreacodeByCity( "南宁" ) << '\n';
std::cout << "find 梧州" << "\n result is:" << pm.GetAreacodeByCity( "梧州" ) << '\n';
std::cout << "find 0771" << "\n result is:" << pm.GetCityByAreacode( "0771" ) << '\n';
std::cout << "find 0774" << "\n result is:" << pm.GetCityByAreacode( "0774" ) << '\n';
std::cin.get( );
return 0;
}
void PhoneManager::Init( void )
{
_bmValues.insert( bm_type::value_type( "0771", "南宁" ) );
_bmValues.insert( bm_type::value_type( "0772", "柳州" ) );
_bmValues.insert( bm_type::value_type( "0773", "桂林" ) );
}
std::string PhoneManager::GetAreacodeByCity( std::string strCity ) const
{
right_const_iterator it;
it = _bmValues.right.find( strCity );
if ( it != _bmValues.right.end( ) )
return it->second;
return "";
}
std::string PhoneManager::GetCityByAreacode( std::string strAreacode ) const
{
left_const_iterator it;
it = _bmValues.left.find( strAreacode );
if ( it != _bmValues.left.end( ) )
return it->second;
return "";
}
void PhoneManager::ListAll( void ) const
{
left_const_iterator it;
for ( it = _bmValues.left.begin( ); it != _bmValues.left.end( ); ++it ) {
std::cout << it->first << ' ' << it->second << '\n';
}
}
有时候, 我们觉得 it->first, it->second看起来很别扭, 让人觉得迷惑, 不知道 first和 second是啥, 这个时候, 我们可以使用标签功能.
2 tagged< std::string, areacode>, // 在这里加标签
3 tagged< std::string, city >
4 > bm_type;
5 typedef bm_type::value_type position;
6 bm_type bmTest;
7 bmTest.insert( position( "0771", "南宁" ) );
8 for ( bm_type::map_by<areacode>::const_iterator // 不用使用.left
9 i = bmTest.by<areacode>().begin(); // 这里也不必指定 .left
10 i != bmTest.by<areacode>().end( );
11 ++i ) {
12 std::cout << i->get<areacode>( ) // 这里可以很明确地指示使用areacode
13 << "<-->"
14 << i->get<city>( ) // 还是city, 而不用去使用混乱的first和second
15 << '\n';
16 }
17
最后, 要说一下关于重复键. BOOST里没有 multibimap, 但是我们可以充分利用模板的特性. 例子好说明:
拿例子来说, 每个身份证都对应一个人的名字, 但人名是有重复的. 我们可以这样做:
2
3 typedef boost::bimap<
4 tagged< std::string, id>,
5 multiset_of< tagged< std::string, name> > // 这里使用multiset_of
6 > bm_type;
注意, 映射中默认都是排过序的, 如果不需要排序, 可以使用 unordered_set_of.
参考资料:
boost 1.37.0 中文文档