zoukankan      html  css  js  c++  java
  • c++ map 使用自定义结构做关键字

    map在STL中的定义

    template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>

     第一个参数Key是关键字类型

    第二个参数T是值类型

    第三个参数Compare是比较函数(仿函数)

    第四个参数是内存配置对象

    map内部存储机制实际是以红黑树为基础,红黑树在插入节点时,必须依照大小比对之后在一个合适的位置上执行插入动作。所以作为关键字,起码必须有“<”这个比较操作符。我们知道,int,float,enum,size_t等等简单关键字,都有内置的比较函数,与map搭配无论是插入还是查找,都没什么问题。但是作为复杂数据类型,如果没有明确定义“<”比较操作符,就不能与map直接搭配使用,除非我们自己定义第三个参数。

    在选择map的关键字时,注意以下两点,同时这两点也是改错的方法:

    a) 关键字明确定义“<”比较操作符

    b) 没有“<”比较操作符,自定义仿函数替代第三个参数Compare,该仿函数实现“()”操作符,提供比较功能。插入时各节点顺序以该仿函数为纲。

    以std::pair为关键字掺入map
    下面我们先写一个有错误的函数,在分析错误原因之后,逐步进行修正。

    #include <map>
    int main()
    {
           std::map<std::pair<int, int>, int> res;
           res.insert(std::make_pair(12,33), 33);
    }

     这个程序一定失败,如果非要如此使用,上述a方法显然不适合,std::pair是已定义好的结构体不可修改。只能使用b方法了,定义一个比较类改造如下:

        #include <map>  
          
        struct comp  
          
        {  
          
               typedef std::pair<int, int> value_type;  
          
               bool operator () (const value_type & ls, const value_type &rs)  
          
               {  
          
                      return ls.first < rs.first || (ls.first == rs.first && ls.second < rs.second);  
          
               }  
          
        };  
          
        int main()  
          
        {  
          
               std::map<std::pair<int, int>, int, comp> res;  
          
               res.insert(std::make_pair(std::make_pair(12,33), 33));  
          
               res.insert(std::make_pair(std::make_pair(121,331), 331));  
          
               res.insert(std::make_pair(std::make_pair(122,332), 332));  
          
                
          
               std::map<std::pair<int, int>, int, comp>::iterator it = res.find(std::make_pair(121,331));  
          
               if (it == res.end())  
          
                      printf("NULL"n");  
          
               else  
          
                      printf("%d %d %d "n", it->first.first, it->first.second, it->second);  
          
            return 0;  
          
        }  

    以结构体或类为关键字插入map

        #include <map>  
          
        struct st  
          
        {  
          
               int a, b;  
          
               st():a(0), b(0){}  
          
               st(int x, int y):a(x), b(y){}  
          
        };  
          
        int main()  
          
        {  
          
               std::map<struct st, int> res;  
          
               res.insert(std::make_pair(st(1,2), 12));  
          
               res.insert(std::make_pair(st(30,4), 34));  
          
               res.insert(std::make_pair(st(5,6), 56));  
          
                
          
               std::map<struct st, int>::iterator it = res.find(st(30,4));  
          
               if (it == res.end())  
          
                      printf("NULL"n");  
          
               else  
          
                      printf("first:%d second:%d %d"n", it->first.a, it->first.b, it->second);  
          
               return 0;  
          
        }  

    编译这个程序也是错误的,错误意思大概也是没有定义“<”比较函数。因为struct st是我们自己定义的结构体,所以修改这个程序可以使用上面ab两种方法。我们先谈第一种,第一次修改时我也搞错了,我是这样定义比较函数的。

        struct st  
          
        {  
          
               int a, b;  
          
               st():a(0), b(0){}  
          
               st(int x, int y):a(x), b(y){}  
          
        bool operator < (const struct st &rs) {return (this->a < rs.a || (this->a == rs.a && this->b < rs.b));}  
          
        };  


    按照这个改动再次编译程序还是错误,有个如下这样的提示:

    /usr/include/c++/3.2.3/bits/stl_function.h:197: passing `const st' as `this' argument of `bool st::operator<(const st&)' discards qualifiers

       为什么会出现这个 问题呢?我们深入STL的源代码看下。既然说是/usr/include/c++/3.2.3/bits/stl_function.h的197行出了问题,且看这行是什么。

    // One of the @link s20_3_3_comparisons comparison functors@endlink.

        template <class _Tp>

        struct less : public binary_function<_Tp,_Tp,bool>

        {

             bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }

         };

     

    struct st中的“<”在编译后真正是什么样子呢?大概是bool operator < (struct st &ls, const struct st &rs)。在less调用这个比较符时,它都是以const方式传入,不可能再以非const方式调用,故出错。修正如下

    struct st

    {

           int a, b;

           st():a(0), b(0){}

           st(int x, int y):a(x), b(y){}

           friend bool operator < (const struct st &ls, const struct st &rs);

    };

    inline bool operator < (const struct st &ls, const struct st &rs)

    {return (ls.a < rs.a || (ls.a == rs.a && ls.b < rs.b));}

     以友联函数代替函数内部定义的比较操作符,STL内部也多是以这种方式定义的。如果我非要以内部定义的方式呢?可以使用b方法,我们自定义一个比较仿函数,替代默认的less。

    插入函数返回值
           在map容器中插入数据有很多函数可用,这里只讨论最普通的insert操作,在STL中它是这样定义的。

           pair<iterator, bool> insert(const value_type& x);

           map容器不允许键值重复,在执行插入操作后,可以凭借该返回值获取操作结果。返回值是一个迭代器和布尔值的键值对,迭代器指向map中具有该值的元素,布尔值表示是否插入成功。如果布尔值为true,表示插入成功,则迭代器为新插入值在map中的位置;布尔值为false,表示插入失败(已经存在该值),迭代器为原有值在map中的位置。

        #include <map>  
        #include <iostream>  
        using namespace std;  
          
        class Key  
        {  
        public:  
            Key();  
            Key(int v);  
            int _key;  
            ~Key();  
            /*重载<作为成员函数不行,两个操作数都要求是const*/  
            //bool operator <(const Key& key);  
        };  
        bool operator <(const Key &key1,const Key &key2)  
        {  
            if(key1._key<key2._key)  
                return true;  
            else  
                return false;  
        }  
        Key::Key()  
        {  
        }  
        Key::Key(int v)  
        {  
            _key=v;  
        }  
        Key::~Key()  
        {  
        }  
          
        void main()  
        {  
              
            map<Key,int> ClassMap;  
            Key one(1);  
            ClassMap.insert(make_pair(one,1));  
            Key two(2);  
            ClassMap.insert(make_pair(two,2));  
            Key three(3);  
            ClassMap.insert(make_pair(three,3));  
            map<Key,int>::iterator itor=ClassMap.begin();  
            while(itor!=ClassMap.end())  
            {  
                cout<<itor->first._key<<" ~~ "<<itor->second<<endl;  
                ++itor;  
            }  
        }  
    
    

     以上内容是转载 http://blog.csdn.net/xie376450483/archive/2011/04/17/6329408.aspx


    纠正上例中的一个错误,重载<的时候,也可以这么做:

    #include <map>  
        #include <iostream>  
        using namespace std;  
          
        class Key  
        {  
        public:  
            Key();  
            Key(int v);  
            int _key;  
            ~Key();  
           
            bool operator <(const Key& key) const;  
        };  
        bool Key::operator <(const Key &key)  const
        {  
            if(this->_key<key._key)  
                return true;  
            else  
                return false;  
        }  
        Key::Key()  
        {  
        }  
        Key::Key(int v)  
        {  
            _key=v;  
        }  
        Key::~Key()  
        {  
        }  
          
        void main()  
        {  
              
            map<Key,int> ClassMap;  
            Key one(1);  
            ClassMap.insert(make_pair(one,1));  
            Key two(2);  
            ClassMap.insert(make_pair(two,2));  
            Key three(3);  
            ClassMap.insert(make_pair(three,3));  
            map<Key,int>::iterator itor=ClassMap.begin();  
            while(itor!=ClassMap.end())  
            {  
                cout<<itor->first._key<<" ~~ "<<itor->second<<endl;  
                ++itor;  
            }  
        }  



  • 相关阅读:
    计算机图形学和OpenGL(二)坐标系和绘制点线函数
    计算机图形学和OpenGL(一)OpenGL初步
    C++ 实现链表常用功能
    Cocos2d-x环境搭建
    2014年学习计划
    2013年终总结
    AS3开发必须掌握的内容
    starling性能优化
    后补个2012年的总结吧
    原生javascript实现图片懒加载
  • 原文地址:https://www.cnblogs.com/zhubaohua-bupt/p/7182799.html
Copyright © 2011-2022 走看看