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.
举例说明, 假我们要做一个电话簿, 有区号-城市的对应关系, 有时候我们有区号, 想得到城市, 或是有城市
想得到区号, 我们可能需要这样一个双向映射关系的电话簿, 我们可以这样:
1
typedef boost::bimap
<
std::
string
,std::
string
>
bm_type;
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 ); 那么我们
可以实现如下:
1
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就成了.
贴出完整源代码:
代码
//
bimap.cpp : 定义控制台应用程序的入口点。
//
#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是啥, 这个时候, 我们可以使用标签功能.
1
typedef boost::bimap
<
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, 但是我们可以充分利用模板的特性. 例子好说明:
拿例子来说, 每个身份证都对应一个人的名字, 但人名是有重复的. 我们可以这样做:
1
#include
<
boost
/
bimap
/
multiset_of.hpp
>
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 中文文档