boost中bimap双向映射的初级学习

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

原文地址:https://www.cnblogs.com/lin1270/p/1933908.html