zoukankan      html  css  js  c++  java
  • 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 中文文档

  • 相关阅读:
    zbb20181207 springboot @ConfigurationProperties使用
    zbb20181206 logback,lombok 默认日志logback配置解析
    Spring Boot (8) 全局异常处理
    Spring Boot (7) JdbcTemplate访问数据库
    Spring Boot (6) Spring Data JPA
    Spring Boot (4) 静态页面和Thymeleaf模板
    Spring Boot (3) 热部署devtools
    Spring Boot (2) Restful风格接口
    Spring Boot (1) 构建第一个Spring Boot工程
    idea使用maven搭建ssm框架实现登陆商品增删改查
  • 原文地址:https://www.cnblogs.com/lin1270/p/1933908.html
Copyright © 2011-2022 走看看