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 中文文档