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

  • 相关阅读:
    翻转单词顺序
    java layout 表格项增加、删除、修改
    Hadoop学习之HBase
    protected的一些功能
    hdu4431 Mahjong
    kendo ui gird温馨提示(使用本地数据) 一个
    TOP计划猿10最佳实践文章
    Java高级应用(一个)-文件夹监控服务
    BSD介绍
    获取编译学习笔记 (十三)—— 外部中断
  • 原文地址:https://www.cnblogs.com/lin1270/p/1933908.html
Copyright © 2020-2023  润新知