vector_map 为什么比map效率高

Effective STL中说过,std::map 是一个比较通用的实现,如果你注重效率的话,Hash容器 是个更好的选择,如果你的操作,主要是(先插入数据,查找,最后删除),那么用vector来实现map,效率也会更高。 从效率的角度看,map只适合那种,需要不断插入和删除,期间夹杂查找的情形。

vector_map 为什么比map效率高

  1. vector是线性存储,map是二叉树树形,所以vector内存访问的局部性更好
  2. vector,  一次分配一个比较大的空间(2^n的分配方式), map每次都需要 new 或delele 一个树结点, 内存分配是很耗时的。
  3. vector_map, 可以在数据构造阶段,使用push_back, 填充完,数据后调用一次sort就可以了(快速排序或堆排序), 而map每次insert都是一次查找和树的旋转操作,整个过程就像是个插入排序。
  4. vector_map, 中的查找,而二分查找,时间复杂度是稳定的log(n), 而map是在log(n) 和 2* log(n)之间 (因为map是红黑树树实现,不是平衡二差树)
  5. vector比map消耗更少的内存,vector内部是数组,辅助数据也很少, map是树形结构,有至少3个指针来维持关系。

 

被滥用的map

       为什么大家一说到key,value 容器,就想到map, 因为 STL一开始只实现了map,  hash还是非标准的,但现实是我们大多数时候需要的只是 std:tr1::unorder_map, std::map 有大小关系, unorder_map没有。std::map的确很方便,但效率确实不高。

      对于写高性能的后台程序来说,只在很少需要的调用的地方,才可以使用std::map. 比如 配置文件的读取(只有启动的时候调用). 对于像 HTTP 请求参数解析或 HTTP header的解析,最好不要用map。

如果用了map,记得把这个map全局化,并不要调用map.clear(). 应该只去清除map的值,保留map的key,比如定义个clear_value(map)函数,这样也能提高些效率。

 

下面是我的vector_map实现:

#ifndef __VECTOR_MAP_H__ 
#define __VECTOR_MAP_H__ 
#include  
#include  
#include  
#include

//wrapped vector for map 
template > 
class vector_map_basic: public std::vector > { 
public: 
    typedef compare_t key_compare; 
    typedef key_t key_type; 
    typedef mapped_t mapped_type; 
    typedef std::pair value_type; 
    typedef vector_map_basic this_type; 
    typedef std::vector container_type;

#define THIS_TYPE vector_map_basic

    void push_back(key_type const &key, mapped_type const &mapped) { 
        push_back(make_pair(key, mapped)); 
    }

    class compare_for_find: public std::binary_function
            bool> { 
    public: 
        explicit compare_for_find(key_compare const &comp) : 
            comp_(comp) { 
        } 
        inline 
        bool operator()(value_type const &node, key_type const &key) { 
            return comp_(node.first, key); 
        }

        key_compare comp_; 
    };

    class compare_for_sort: public std::binary_function
            bool> { 
    public: 
        explicit compare_for_sort(key_compare const &comp) : 
            comp_(comp) { 
        }

        inline 
        bool operator()(value_type const &left, value_type const &right) { 
            return comp_(left.first, right.first); 
        } 
        key_compare comp_; 
    };

    //get 
    bool get(key_type const &key, mapped_type & result) const { 
        typename this_type::const_iterator it = find(key); 
        if (it != data().end()) { 
            result = it->second; 
            return true; 
        } 
        return false; 
    }

    inline std::pair
            typename THIS_TYPE::const_iterator> equal_range(key_type const &key) const { 
        return std::equal_range(data().begin(), data().end(), key, 
                compare_for_find(key_comp_)); 
    }

    inline std::pair equal_range( 
            key_type const &key) { 
        return std::equal_range(data().begin(), data().end(), key, 
                compare_for_find(key_comp_)); 
    }

    typename THIS_TYPE::const_iterator find(key_type const &key) const { 
        typename this_type::const_iterator it = std::lower_bound( 
                data().begin(), data().end(), key, compare_for_find(key_comp_)); 
        typename this_type::iterator iend = data().end(); 
        if (it != iend && !key_comp_(key, it->first)) 
            return it; 
        return iend; 
    }

    typename THIS_TYPE::iterator find(key_type const &key) { 
        typename this_type::iterator it = std::lower_bound(data().begin(), 
                data().end(), key, compare_for_find(key_comp_)); 
        typename this_type::iterator iend = data().end(); 
        if (it != iend && !key_comp_(key, it->first)) 
            return it; 
        return iend; 
    }

    key_compare key_comp() const { 
        return key_comp_; 
    }

    //sort 
    void sort() { 
        typename this_type::compare_for_sort comp(this->key_comp_); 
        std::sort(data().begin(), data().end(), comp); 
    }

    // 
    void set_default_value(mapped_type const &def) { 
        mapped_default_ = def; 
    }

    mapped_type default_value() const { 
        return mapped_default_; 
    }

    typename THIS_TYPE::container_type const & 
    data() const { 
        return *this; 
    }

    typename THIS_TYPE::container_type & 
    data() { 
        return *this; 
    }

public: 
    key_compare key_comp_; 
    mapped_type mapped_default_;

#undef THIS_TYPE 
};

//wrapped vector for map 
template > 
class vector_map: public vector_map_basic { 
public:

#define THIS_TYPE vector_map

    typedef vector_map this_type; 
    typedef vector_map_basic parent_type;

    vector_map() { 
    }

    //for fast insert

    void push_back(typename THIS_TYPE::value_type const &value) { 
        push_back(value); 
    }

    void push_back(typename THIS_TYPE::key_type const &key, 
            typename THIS_TYPE::mapped_type const &mapped) { 
        push_back(make_pair(key, mapped)); 
    }

    void set(typename THIS_TYPE::key_type const &key, 
            typename THIS_TYPE::mapped_type const & val) { 
        typename this_type::iterator iend = this->data().end(), it = 
                std::lower_bound(this->data().begin(), iend, key, 
                        typename this_type::compare_for_find(this->key_comp_)); 
        if (it != iend && !key_comp_(key, it->first)) { 
            it -> second = val; 
        } else { 
            insert(it, make_pair(key, val)); 
        } 
    }

    //like map insert 
    void insert(typename this_type::value_type const &value) { 
        this->set(value.first, value.second); 
    }

    void insert(typename this_type::iterator pos, 
            typename this_type::value_type const &value) { 
        this->data().insert(pos, value); 
    }

    //get 
    bool get(typename THIS_TYPE::key_type const &key, 
            typename THIS_TYPE::mapped_type & result) const { 
        return parent_type::get(key, result); 
    }

    typename THIS_TYPE::mapped_type const & 
    operator[](typename THIS_TYPE::key_type const &key) const { 
        typename this_type::mapped_type result = this->mapped_default_; 
        get(key, result); 
        return result; 
    }

    typename THIS_TYPE::mapped_type & 
    operator[](typename THIS_TYPE::key_type const &key) { 
        typename this_type::iterator iend = this->data().end(); 
        typename this_type::iterator it = std::lower_bound( 
                this->data().begin(), iend, key, 
                typename this_type::compare_for_find(this->key_comp_)); 
        if (it != iend && !key_comp_(key, it->first)) { 
            return it -> second; 
        } 
        return this->data().insert(it, make_pair(key, this->mapped_default_))->second; 
    } 
#undef THIS_TYPE 
};

template 
void clear_value(like_map_t &map, val_t const & null_val) 
    for (typename like_map_t::iterator it = map.begin(), iend = map.end(); it 
            != iend; ++it) { 
        it->second = null_val; 
    } 
}

template 
void clear_value(like_map_t &map) 
    clear_value(map, typename like_map_t::mapped_type()); 
}

#endif //__VECTOR_MAP_H__

 

使用clear_value, 可以减少内存释放和分配,从而提高效率。

 

对于有些后台程序,只关心固定的param或http header, 那么那么还可以定制个数据结构,那样速度更快,下次介绍fixed_map.

WEB后台,还有影响效率的地方是使用滥用std::string,  这个可以实现个ref_str来解决。这个也下次介绍吧。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值