STL中的vector_map

来源:互联网 发布:预测股票涨跌软件 编辑:程序博客网 时间:2024/06/07 16:47
  Effective STL中说过,std::map 是一个比较通用的实现,如果你注重效率的话,Hash容器 是个更好的选择,如果你的操作,主要是(先插入数据,查找,最后删除),那么用vector来实现map,效率也会更高。 从效率的角度看,map只适合那种,需要不断插入和删除,期间夹杂查找的情形。
  vector_map 为什么比map效率高
  vector是线性存储,map是二叉树树形,所以vector内存访问的局部性更好
  vector,  一次分配一个比较大的空间(2^n的分配方式), map每次都需要 new 或delele 一个树结点, 内存分配是很耗时的。
  vector_map, 可以在数据构造阶段,使用push_back, 填充完,数据后调用一次sort就可以了(快速排序或堆排序), 而map每次insert都是一次查找和树的旋转操作,整个过程就像是个插入排序。
  vector_map, 中的查找,而二分查找,时间复杂度是稳定的log(n), 而map是在log(n) 和 2* log(n)之间 (因为map是红黑树树实现,不是平衡二差树)
  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实现:
  1. #ifndef __VECTOR_MAP_H__ 
  2. #define __VECTOR_MAP_H__ 
  3. #include <vector> 
  4. #include <algorithm> 
  5. #include <utility> 
  6. #include <functional>
  7. //wrapped vector for map 
  8. template<typename key_t, typename mapped_t, class compare_t = std::less<key_t> > 
  9. class vector_map_basic: public std::vector<std::pair<key_t, mapped_t> > { 
  10. public: 
  11.     typedef compare_t key_compare; 
  12.     typedef key_t key_type; 
  13.     typedef mapped_t mapped_type; 
  14.     typedef std::pair<key_t, mapped_t> value_type; 
  15.     typedef vector_map_basic<key_t, mapped_t, compare_t> this_type; 
  16.     typedef std::vector<value_type> container_type;
  17. #define THIS_TYPE vector_map_basic<key_t, mapped_t, compare_t>
  18.     void push_back(key_type const &key, mapped_type const &mapped) { 
  19.         push_back(make_pair(key, mapped)); 
  20.     }
  21.     class compare_for_find: public std::binary_function<value_type, key_type, 
  22.             bool> { 
  23.     public: 
  24.         explicit compare_for_find(key_compare const &comp) : 
  25.             comp_(comp) { 
  26.         } 
  27.         inline 
  28.         bool operator()(value_type const &node, key_type const &key) { 
  29.             return comp_(node.first, key); 
  30.         }
  31.         key_compare comp_; 
  32.     };
  33.     class compare_for_sort: public std::binary_function<value_type, value_type, 
  34.             bool> { 
  35.     public: 
  36.         explicit compare_for_sort(key_compare const &comp) : 
  37.             comp_(comp) { 
  38.         }
  39.         inline 
  40.         bool operator()(value_type const &left, value_type const &right) { 
  41.             return comp_(left.first, right.first); 
  42.         } 
  43.         key_compare comp_; 
  44.     };
  45.     //get 
  46.     bool get(key_type const &key, mapped_type & result) const { 
  47.         typename this_type::const_iterator it = find(key); 
  48.         if (it != data().end()) { 
  49.             result = it->second; 
  50.             return true; 
  51.         } 
  52.         return false; 
  53.     }
  54.     inline std::pair<typename THIS_TYPE::const_iterator, 
  55.             typename THIS_TYPE::const_iterator> equal_range(key_type const &key) const {
  56.         return std::equal_range(data().begin(), data().end(), key, 
  57.                 compare_for_find(key_comp_)); 
  58.     }
  59.     inline std::pair<typename THIS_TYPE::iterator, typename THIS_TYPE::iterator> equal_range( 
  60.             key_type const &key) { 
  61.         return std::equal_range(data().begin(), data().end(), key, 
  62.                 compare_for_find(key_comp_)); 
  63.     }
  64.     typename THIS_TYPE::const_iterator find(key_type const &key) const { 
  65.         typename this_type::const_iterator it = std::lower_bound( 
  66.                 data().begin(), data().end(), key, compare_for_find(key_comp_)); 
  67.         typename this_type::iterator iend = data().end(); 
  68.         if (it != iend && !key_comp_(key, it->first)) 
  69.             return it; 
  70.         return iend; 
  71.     }
  72.     typename THIS_TYPE::iterator find(key_type const &key) { 
  73.         typename this_type::iterator it = std::lower_bound(data().begin(), 
  74.                 data().end(), key, compare_for_find(key_comp_)); 
  75.         typename this_type::iterator iend = data().end(); 
  76.         if (it != iend && !key_comp_(key, it->first)) 
  77.             return it; 
  78.         return iend; 
  79.     }
  80.     key_compare key_comp() const { 
  81.         return key_comp_; 
  82.     }
  83.     //sort 
  84.     void sort() { 
  85.         typename this_type::compare_for_sort comp(this->key_comp_); 
  86.         std::sort(data().begin(), data().end(), comp); 
  87.     }
  88.     // 
  89.     void set_default_value(mapped_type const &def) { 
  90.         mapped_default_ = def; 
  91.     }
  92.     mapped_type default_value() const { 
  93.         return mapped_default_; 
  94.     }
  95.     typename THIS_TYPE::container_type const & 
  96.     data() const { 
  97.         return *this; 
  98.     }
  99.     typename THIS_TYPE::container_type & 
  100.     data() { 
  101.         return *this; 
  102.     }
  103. public: 
  104.     key_compare key_comp_; 
  105.     mapped_type mapped_default_;
  106. #undef THIS_TYPE 
  107. };
  108. //wrapped vector for map 
  109. template<typename key_t, typename mapped_t, class compare_t = std::less<key_t> > 
  110. class vector_map: public vector_map_basic<key_t, mapped_t, compare_t> { 
  111. public:
  112. #define THIS_TYPE vector_map<key_t, mapped_t,compare_t>
  113.     typedef vector_map this_type; 
  114.     typedef vector_map_basic<key_t, mapped_t, compare_t> parent_type;
  115.     vector_map() { 
  116.     }
  117.     //for fast insert
  118.     void push_back(typename THIS_TYPE::value_type const &value) { 
  119.         push_back(value); 
  120.     }
  121.     void push_back(typename THIS_TYPE::key_type const &key, 
  122.             typename THIS_TYPE::mapped_type const &mapped) { 
  123.         push_back(make_pair(key, mapped)); 
  124.     }
  125.     void set(typename THIS_TYPE::key_type const &key, 
  126.             typename THIS_TYPE::mapped_type const & val) { 
  127.         typename this_type::iterator iend = this->data().end(), it = 
  128.                 std::lower_bound(this->data().begin(), iend, key, 
  129.                         typename this_type::compare_for_find(this->key_comp_)); 
  130.         if (it != iend && !key_comp_(key, it->first)) { 
  131.             it -> second = val; 
  132.         } else { 
  133.             insert(it, make_pair(key, val)); 
  134.         } 
  135.     }
  136.     //like map insert 
  137.     void insert(typename this_type::value_type const &value) { 
  138.         this->set(value.first, value.second); 
  139.     }
  140.     void insert(typename this_type::iterator pos, 
  141.             typename this_type::value_type const &value) { 
  142.         this->data().insert(pos, value); 
  143.     }
  144.     //get 
  145.     bool get(typename THIS_TYPE::key_type const &key, 
  146.             typename THIS_TYPE::mapped_type & result) const { 
  147.         return parent_type::get(key, result); 
  148.     }
  149.     typename THIS_TYPE::mapped_type const & 
  150.     operator[](typename THIS_TYPE::key_type const &key) const { 
  151.         typename this_type::mapped_type result = this->mapped_default_; 
  152.         get(key, result); 
  153.         return result; 
  154.     }
  155.     typename THIS_TYPE::mapped_type & 
  156.     operator[](typename THIS_TYPE::key_type const &key) { 
  157.         typename this_type::iterator iend = this->data().end(); 
  158.         typename this_type::iterator it = std::lower_bound( 
  159.                 this->data().begin(), iend, key, 
  160.                 typename this_type::compare_for_find(this->key_comp_)); 
  161.         if (it != iend && !key_comp_(key, it->first)) { 
  162.             return it -> second; 
  163.         } 
  164.         return this->data().insert(it, make_pair(key, this->mapped_default_))->second; 
  165.     } 
  166. #undef THIS_TYPE 
  167. };
  168. template<typename like_map_t, typename val_t> 
  169. void clear_value(like_map_t &map, val_t const & null_val) { 
  170.     for (typename like_map_t::iterator it = map.begin(), iend = map.end(); it 
  171.             != iend; ++it) { 
  172.         it->second = null_val; 
  173.     } 
  174. }
  175. template<typename like_map_t> 
  176. void clear_value(like_map_t &map) { 
  177.     clear_value(map, typename like_map_t::mapped_type()); 
  178. }
  179. #endif //__VECTOR_MAP_H__
复制代码
  使用clear_value, 可以减少内存释放和分配,从而提高效率。
  对于有些后台程序,只关心固定的param或http header, 那么那么还可以定制个数据结构,那样速度更快,下次介绍fixed_map.
  WEB后台,还有影响效率的地方是使用滥用std::string,  这个可以实现个ref_str来解决。这个也下次介绍吧
原创粉丝点击