您的位置:首页 > 编程语言 > C语言/C++

用boost::bimap做排行榜时查阅的资料

2014-03-21 12:49 246 查看
参考资料地址:http://blog.csdn.net/weiwangchao_/article/details/7290793

参考资料地址:http://taotaocoder.blog.163.com/blog/static/2002282742011102524124598/

参考资料地址:http://www.cnblogs.com/kex1n/archive/2010/03/25/2286505.html


bimap是boost中很重要的一个容器,可以进行双向的查找和替换,这样弥补了如果map和multimap需要找到data所对应的键值。循环遍历元素,才能找到相应的键值,再删除,最后替换的不足。

但是boost的模板源编程又有着先天的缺点,就是编译错误不容易找到,编译时间有点长。但是如果长期使用boost,知道常见的错误,这个缺点还是可以慢慢克服的;虽然编译时间是有点长,但是比起自己一行一行自己写,还是说的过去的。

下面是需要的一些头,如果只是简单使用bimap,仅引入#include 就可以了

#include <iostream>  

#include <map>  

#include <boost/foreach.hpp>  

#include <boost/typeof/typeof.hpp>  

#include <boost/bimap.hpp>  

#include <boost/bimap/set_of.hpp>  

#include <boost/bimap/vector_of.hpp>  

//#include <boost/bimap/tags/tagged.hpp>  

usingnamespace boost::bimaps;  

usingnamespace boost;  

usingnamespace std;  

首先写出一个打印bimap的工具函数,这个函数不仅可以打印bimap也可以打印map和multimap。

这里用到了boost很常用的BOOST_AUTO和BOOST_FOREACH。个人比较倾向于我写的第一个实现。

如果在程序灵活的使用boost的一些宏是可以很多的代码的。

这里BOOST_FOREACH要比BOOST_AUTO要简明一些。但是试想如果不能用这两个的话,for循环的第一个参数应该写多长啊。

//打印所有元素  

template<classT>  

voidprint_map(T &m)  

{  

    //方式一 比较喜欢用的方式  

    BOOST_FOREACH(T::value_type v,m)  

    {  

        cout<<v.first<<" "<<v.second<<endl;  

    }  

    //方式二  

//  for (BOOST_AUTO(pos,m.begin());pos!=m.end();++pos)  

//  {  

//      cout<<pos->first<<"--------"<<pos->second<<endl;  

//  }  

}  

切记 简单bimap key/value 从两个个方向看必须都是唯一,虽然这个规则可以在后面改变

typedefbimap<int,std::string> bm_t;  

如果插入的值不唯一,将会显示第一次插入的结果。

下面是左值重复插入测试

intmain()  

{  

    std::map<int,int> test;  

    //先创建  

    test[1] = 2;  

    //再修改  

    test[1] = 4;  

    cout<<test[1]<<endl;   //结果:4  

   

    //bimap左值重复测试  

    bm_t col;  

    col.left.insert(make_pair(5,"hello"));  

    //虽然无效,但是可以插入  

    col.left.insert(make_pair(5,"world"));  

    //测试显示的是第一次插入的值  

    BOOST_AUTO(iter,col.left.find(5));  

    cout<<"left euql:"<<iter->second<<endl;   //结果:hello  

   

    //bimap右值重复测试  

    col.right.insert(make_pair("hello",10));  

    BOOST_AUTO(iter2,col.right.find("hello"));  

    //对于右值查询,常量输出的方向应该相反,原first变seoond  

    //测试同样显示的是第一次插入的值  

    cout<<"right equal:"<<iter2->second<<endl;//结果:5  

不能使用map的方式要访问简单的bimap,否则会造成

编译错误,提示 error C2664: ‘boost::mpl::assertion_failed’ : cannot convert parameter 1 from ‘boost::mpl::failed

对于模版源编程,熟悉一些错误对程序的纠错是非常有好处的

虽然不能像关联数组一样使用operator[],但这个不是绝对的。

可以使用来使用operator[]

cout<<col.left[5]<<endl;  

下面是右值重复插入测试

typedefbm_t::value_type val;  

//不使用左右视图,使用 value_type 插入元素  

col.insert(val(50,"test_value_type"));  

   

typedefbm_t::left_value_type left_val;  

//使用 left_value_type 插入元素  

//同理 right_value_type 插入元素  

col.left.insert(left_val(100,"left_value_type"));  

   

//传入一个左视图的结果集  

print_map(col.left);  

使用bimap库的一些类和方法可以使用可以使用operator[],而且可以不唯一key/value的bimap,但必须保证左视图为有序,右视图为随意访问类型。

bimap<boost::bimaps::set_of<int>,boost::bimaps::vector_of<std::string> > bm_multi;  

bm_multi.left.insert(make_pair(1,"111"));  

bm_multi.left[2] = "222";  

bm_multi.left[300] = "bimap";  

   

cout<<"use operator: "<<bm_multi.left[300]<<endl;  

print_map(bm_multi.left);  

//输出  

//1 111  

//2 222  

//300 bimap  

对于常见的访问类型,见下:

set_of , multiset_of , unordered_set_of ,unordered_multiset_of : 可以做键值索引

list_of ,vector_of ,unconstrained_set_of :不能用作键值索引

关于这部分的具体内容可以参考《Boost程序库完全开发指南》P264

关于 boost bimap 的tagged,使用boost tagged 给左右视图增加标签 这个功能在vs下不太稳定,但也可能是本人编译器的问题

bimap<tagged<int,structid> ,tagged<std::string ,structname> > bm_tag_test;  

 bm_tag_test.by<id>{}.insert(make_pair(1,"hello"));  

 bm_tag_test.by<id>{}.insert(make_pair(2,"world"));  

  

 bm_tag_test.by<name>{}.insert(make_pair("test",3));  

  

 print_map(bm_tag_test.by<name>());
 

有时候, 我们觉得 it->first, it->second看起来很别扭,  让人觉得迷惑, 不知道 first和 second是啥, 这个时候, 我们可以使用标签功能.

typedef boost::bimap<

    tagged< std::string, areacode>,  // 在这里加标签

    tagged< std::string, city    >

> bm_type;

typedef bm_type::value_type position;

bm_type bmTest;

bmTest.insert( position( "0771", "南宁" ) );

for ( bm_type::map_by<areacode>::const_iterator // 不用使用.left

    i  = bmTest.by<areacode>().begin();  // 这里也不必指定 .left

    i != bmTest.by<areacode>().end( );

    ++i ) {

    std::cout << i->get<areacode>( )  // 这里可以很明确地指示使用areacode

              << "<-->"

              << i->get<city>( )      // 还是city, 而不用去使用混乱的first和second

              << '\n';

}

 

最后, 要说一下关于重复键. BOOST里没有 multibimap, 但是我们可以充分利用模板的特性. 例子好说明:

拿例子来说, 每个身份证都对应一个人的名字, 但人名是有重复的. 我们可以这样做:

#include <boost/bimap/multiset_of.hpp> 

typedef boost::bimap< tagged < std::string, id >, multiset_of < tagged < std::string, name > > > bm_type;

Boost.Bimap 是一个C++的双向 map 库。使用 Boost.Bimap,你可以创建两个类型都可用作键值的关联容器。
bimap<X,Y>
 可以被视为 
std::map<X,Y>
 加上 
std::map<Y,X>
。如果你知道如何使用标准容器,那么
bimap 的学习曲线就几乎是平的。在 Boost.Bimap 中作出了大量的努力,以符合STL的命名规则。本库是按照与常见STL容器相匹配的方式进行设计的。

记住,
bm
 可单独用作关系的 set。我们可以插入元素,或者使用该视图进行遍历。

 

boost::bimap - 双向映射

定义一个 bimap :

#include bimap bm;

它有3个不同的视图:

bm.left : 是一个兼容于 std::map 类型的东西.

bm.right: 是一个兼容于 std:::map 类型的东西.

bm 是一个兼容于 std::set< relation 类型的东西.

 例如我们有一个输出map的函数如下:

template< class MapType > void print_map(const MapType & m)

{

      typedef typename MapType::const_iterator const_iterator;

     for( const_iterator iter = m.begin(), iend = m.end(); iter != iend; ++iter )

      {

         std::cout << iter->first << "-->" << iter->second << std::endl;

       }

}

它的参数可以接受一个 std::map 对象. 所以它也可以接受如下调用:

print_map( bm.left );

print_map( bm.right );

下边我们定义一个整数和字符串的双向映射: 

typedef boost::bimap< int, std::string > bm_type;

 bm_type bm;

向其插入数据:

bm.insert( bm_type::value_type(1, "one" ) );

bm.insert( bm_type::value_type(2, "two" ) );

 输出刚才插入的数据:

 std::cout << "There are " << bm.size() << "relations" << std::endl; for( bm_type::const_iterator iter = bm.begin(), iend = bm.end(); iter != iend; ++iter )

 {

 std::cout << iter->left << " <--> " << iter->right << std::endl;

 }

接着我们使用它的 left 视图(就像在使用一个std::map): //left视图的迭代器类型

 typedef bm_type::left_map::const_iterator left_const_iterator;

for( left_const_iterator left_iter = bm.left.begin(), iend = bm.left.end(); left_iter != iend; ++left_iter )

{

   std::cout << left_iter->first << " --> " << left_iter->second << std::endl;

}

bm_type::left_const_iterator left_iter = bm.left.find(2);

assert( left_iter->second == "two" ); // 再通过左视图向 bm 插入数据 //

它和直接用 bm.insert( bm_type::value_type(3,"three") ); 效果一样

bm.left.insert( bm_type::left_value_type( 3, "three" ) );

同样的. 我们可以使用它的 right视图 : // 通过 string 查找

bm_type::right_const_iterator right_iter = bm.right.find("two"); assert( right_iter->second == 2 ); // 调用 at() assert( bm.right.at("one") == 1 ); // 删除 "two" 对应的关系 bm.right.erase("two");

 最后. 缺省时在 std::map 中. 我们插入 ("1", 1) 后再插入 ("one", 1) 是可以的.

但这在bimap中不行. 因为它左右两个都可以做键值. 要求它们两者都必须是唯一的. 但这只是它缺省时的样子. bimap可以通过模板参数来定制它一些特征: 例如可以指定是否需要 一对多 的映射关系: 可以一个 x 对应多个 y. 可以多个 x 对应一个 y. 也可以多个 x 对应多个 y. 还可以指定是否要求 left视图 或 right视图 或 两者 有序. 如果不要求有序的话.
它可以用 hash表来实现底层.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  boost bimap c++