STL源码剖析-map

1.容器rb_tree

Red-Black tree(红黑树)是平衡二元搜寻树(balanced binary search tree)中常被使用的一种平衡二元搜寻树的特点:排列规则有利于search和insert,并保持适度平衡-无任何节点过深

rb_tree提供遍历操作以及iterators

按正常规则(++ite)遍历,便能获得排序状态(sorted)

我们不应该使用rb_tree的iterators改变元素值(因为元素有其严谨排列规则)。编程里面(programming leve)并未阻绝此事。如此设计是正确的,因为rb_tree即将为set和map服务(做为其底部支持),而map允许元素的data被改变,只有元素的key才是不可被改变的

rb_tree提供两种insertion操作:insert_unique()insert_equal()。前者表示节点的key一定在整个tree中独一无二,否则安插失败。后者表示节点的key可重复

#include <set>
#include <iostream>
using namespace std;

//容器rb_tree
//                    key和data合成value(key|value)
//template<class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc>
//class rb_tree {
//protected:
//    typedef __rb_tree_node<Value> rb_tree_node;
//    ...
//public:
//    typedef rb_tree_node* link_type;
//protected:
//    //RB-tree只以三笔表现他自己
//    size_type node_count; // rb_tree的大小(节点)
//    link_type header;
//    Compare key_compare; //key的大小比较规则,应会是个function object
//};
namespace jj31
{
    void test_Rb_tree()
    {
        //G2.9 vs. G4.9 : 
        //rb_tree => _Rb_tree, 
        //identity<> => _Identity<>
        //insert_unique() => _M_insert_unique()
        //insert_equal() => _M_insert_equal()

        cout << "\ntest_Rb_tree().......... \n";

        _Rb_tree<int, int, _Identity<int>, less<int> > itree;
        cout << itree.empty() << endl;  //1
        cout << itree.size() << endl;   //0

        itree._M_insert_unique(3);
        itree._M_insert_unique(8);
        itree._M_insert_unique(5);
        itree._M_insert_unique(9);
        itree._M_insert_unique(13);
        itree._M_insert_unique(5);  //no effect, since using insert_unique().
        cout << itree.empty() << endl;  //0
        cout << itree.size() << endl;   //5
        cout << itree.count(5) << endl; //1

        itree._M_insert_equal(5);
        itree._M_insert_equal(5);
        cout << itree.size() << endl;   //7, since using insert_equal().
        cout << itree.count(5) << endl; //3       
    }                                                            
}
int main() {
    jj31::test_Rb_tree();
    return 0;
}

2.容器map,multimap

(1)map/multimap以rb_tree为底层结构,因此有元素自动排序特性,排序的依据是key.                           
(2)map/multimap提供"遍历"操作及iterators,按正常规则(++ite)遍历,便能获得排序状态(sorted)              
(3)我们无法使用map/multimap的iterators改变元素的key(因为key有其严谨的排列规则),但可以用它改变元素的data,
因此,map/multimap内部自动将user指定的key type设为const,如此禁止user对元素的key赋值,map不允许迭代器来改key   

(4)map元素的key必须独一无二,因此其insert()用的是rb_tree的insert_unique                               
   multimap元素的key可以重复,因此其insert()用的是rb_tree的insert_equal

template <class _Key, class _Tp, class _Compare, class _Alloc>                                    
class map {                                                                                         
    public:                                                                                         
        // typedefs:                                                                                
        typedef _Key                  key_type;                                                     
        typedef _Tp                   data_type;                                                    
        typedef _Tp                   mapped_type;                                                  
        typedef pair<const _Key, _Tp> value_type;                                                   
        // key|data,key和data合成value                                                              
        // map/multimap内部自动将user指定的key type设为const,如此禁止user对元素的key赋值            
        typedef _Compare              key_compare;                                                  
    private:                                                                                        
        typedef _Rb_tree<key_type, value_type,                                                      
                _Select1st<value_type>, key_compare, _Alloc> _Rep_type;                             
        _Rep_type _M_t;  // red-black tree representing map                                         
    public:                                                                                         
        typedef typename _Rep_type::iterator iterator;                                              
};
map<int, string> imap -> map<int, string, less<int>, alloc> imap ->                                 
template<int, pair<const int, string>, select1st<pair<const int, string>>, less<int>, alloc> class rb_tree;

3.容器map,独特的operator[]

返回与下标中指定的键关联的数据                                                                      
如果key不存在,则使用默认值创建具有key的对,然后返回该值                                            
 

_Tp& operator[](const key_type& __k) {                                                              
    iterator __i = lower_bound(__k);                                                                
    // __i->first is greater than or equivalent to __k.                                             
    if (__i == end() || key_comp()(__k, (*__i).first))                                              
        __i = insert(__i, value_type(__k, _Tp()));                                                  
    return (*__i).second;                                                                           
} 

lower_bound是二分搜寻的一种版本,试图在sorted[first, last)中寻找元素value                            
若[first, last)拥有value相等的元素(s),便返回一个iterator指向其中第一个元素                          
如果没有这样的元素存在,便返回假设该元素存在时应该出现的位置                                         
lower_bound返回的是 不破坏排序得以安插value的第一个适当位置   

#include <map>
#include <stdexcept>
#include <string>
#include <cstdlib> //abort() and rand() and RAND_MAX
#include <cstdio>  //snprintf()
#include <iostream>
#include <ctime> 
using namespace std;
namespace jj14
{
    long get_a_target_long()
    {
        long target=0;
        cout << "target (0~" << RAND_MAX << "): ";
        cin >> target;
        return target;
    }
    void test_map(long& value)
    {
        cout << "\ntest_map().......... \n";

        map<long, string> c;   
        char buf[10];

        clock_t timeStart = clock();                                
        for(long i=0; i< value; ++i)
        {
            try {
                snprintf(buf, 10, "%d", rand());
                c[i] = string(buf);                     
            }
            catch(exception& p) {
                cout << "i=" << i << " " << p.what() << endl;   
                abort();
            }
        }
        cout << "milli-seconds : " << (clock()-timeStart) << endl;  
        cout << "map.size()= " << c.size() << endl; 
        cout << "map.max_size()= " << c.max_size() << endl;     //178956970

        long target = get_a_target_long();      
        timeStart = clock();        
        auto pItem = c.find(target);                                
        cout << "c.find(), milli-seconds : " << (clock()-timeStart) << endl;         
        if (pItem != c.end())
            cout << "found, value=" << (*pItem).second << endl;
        else
            cout << "not found! " << endl;          

        c.clear();                  
    }                                                            
}

int main() {
    long value;
    cout << "how many elements: ";
    cin >> value;       
    jj14::test_map(value);
}

4.map容器迭代器失效问题

迭代器失效_INGNIGHT的博客-CSDN博客

#include <iostream>
#include <map>
using namespace std;
class Key {
public:
    explicit Key(int num):_num(num) {

    }
    int get_num() const {
        return _num;
    }
    bool operator < (const Key& k) const {
        return get_num() < k.get_num() ? true : false;
    }
public:
    int _num;
};



class CompareKey : public binary_function<Key, Key, bool> {
public:
    bool operator()(const Key& k1, const Key& k2) {
        return k1.get_num() < k2.get_num() ? true : false;
    }
};

int main() {
    //std::map<Key, int, CompareKey> table;
    std::map<Key, int> table;
    table.insert(std::pair<Key, int>(Key(0), 1));
    table.insert(std::pair<Key, int>(Key(1), 1));
    table.insert(std::pair<Key, int>(Key(3), 1));
    table.insert(std::pair<Key, int>(Key(4), 1));
    table.insert(std::pair<Key, int>(Key(5), 1));
    cout << table.begin()->first.get_num() << std::endl;
    cout << table.rbegin()->first.get_num() << std::endl;
    auto ite = table.lower_bound(Key(1));
    cout << ite->first.get_num() << std::endl;;
    ite = table.lower_bound(Key(2));
    cout << ite->first.get_num() << std::endl;;
    ite = table.upper_bound(Key(2));
    cout << ite->first.get_num() << std::endl;;
    ite = table.upper_bound(Key(1));
    cout << ite->first.get_num() << std::endl;;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值