`
aigo
  • 浏览: 2679785 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

map hash_map unordered_map 性能测试

C++ 
阅读更多
测试条件:
gcc version 4.2.1 20070719  [FreeBSD]
FreeBSD  7.2-RELEASE #0: Fri May  1 07:18:07 UTC 2009     root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
Intel(R) Xeon(R) CPU           E5620  @ 2.40GHz 16核
 
测试程序说明:
先准备好n个字符串随机的MD5字符串做为key,然后分别对3个容器进行插入、遍历、查找、删除操作。
例如,n=100的时候,插入是指插入100个随机MD5 key;遍历是指对容器遍历一次;查找是指分别对这个100个随机的MD5 key做查找操作(即查找100次);删除是指挨个删除这个100个随机MD5 key。
 
测试数据如下表:

插入,单位us 100 1K 10K 100K 1M 10M
std::map 241 2833 35888 381214 4439088 62233380
std::ext/hash_map 97 1667 16466 146025 1788446 18512639
std::tr1::unordered_map 77 772 8052 53094 658312 7429297
 

遍历,单位us 100 1K 10K 100K 1M 10M
std::map 11 76 842 11603 155700 1771906
std::ext/hash_map 47 430 4218 39880 470344 4781575
std::tr1::unordered_map 1 1 2 1 2 1
查找,单位us 100 1K 10K 100K 1M 10M
std::map 156 2111 30456 258709 4100260 59064394
std::ext/hash_map 77 774 8056 56974 660231 7705527
std::tr1::unordered_map 77 772 8051 54456 659537 7600263
删除,单位us 100 1K 10K 100K 1M 10M
std::map 291 3641 49584 472414 6675897 92491113
std::ext/hash_map 89 869 9068 86524 964767 10372650
std::tr1::unordered_map 49 480 4879 33087 395098 4369617
结论:
1. std::tr1::unordered_map 与 std::ext/hash_map 
     任何情况下,如果要在这两个容器之间选择的话,我们毫不犹豫应该选择 unordered_map。因为他的性能在上述4中操作中均优于 hash_map,甚至可以说远远优于 hash_map。
 
2. std::tr1::unordered_map 与 std::map 
     map的性能总体来说是最差的。但是,当我们需要一个有序的关联容器的时候,我们必须选择std::map,因为 unordered_map 内部元素不是有序的,这一点从名字都可以看出来。除此之外都应该选择 unordered_map 。
 
3. 上述测试中,unordered_map 的遍历性能几乎是常数级别的,与常识不太相符,需要再研究研究。
 
附录:贴上源代码
说明:与测试程序稍有区别,这里的源码里没有MD5相关的代码以确保其他人能比较方便的直接拿去编译运行。
 
如有错误还请跟帖指出,非常感谢。
 
 
  1. #include <iostream>
  2. #include <string>
  3. #include <sstream>
  4. #include <list>
  5. #include <map>
  6. #include <sys/time.h>
  7. #include <ext/hash_map>
  8. #include <tr1/unordered_map>
  9. namespace zl
  10. { //{{{
  11.     struct equal_to
  12.     {
  13.         bool operator()(const char* s1, const char* s2) const
  14.         {
  15.             return strcmp(s1, s2) == 0;
  16.         }
  17.     };
  18.  
  19.     struct hash_string
  20.         : public std::unary_function<std::string, std::size_t>
  21.         {
  22.             std::size_t
  23.                 operator()(const std::string& __s) const
  24. #ifdef __linux__
  25.                 { return std::tr1::Fnv_hash<>::hash(__s.data(), __s.length()); }
  26. #else
  27.                 { return std::tr1::_Fnv_hash<>::hash(__s.data(), __s.length()); }
  28. #endif
  29.         };
  30.     
  31.     struct hash_charptr
  32.         : public std::unary_function<const char*, std::size_t>
  33.         {
  34.             std::size_t
  35.                 operator()(const char* __s) const
  36. #ifdef __linux__
  37.                 { return std::tr1::Fnv_hash<>::hash(__s, strlen(__s)); }
  38. #else
  39.                 { return std::tr1::_Fnv_hash<>::hash(__s, strlen(__s)); }
  40. #endif
  41.         };
  42. }//}}}
  43. typedef std::list<std::string> string_list;
  44. typedef std::map<std::string, int> string_map;
  45. typedef __gnu_cxx::hash_map<std::string, int, zl::hash_string> string_hash_map;
  46. typedef std::tr1::unordered_map<std::string, int> string_unordered_map;
  47. void fill_list(string_list& slist, size_t count);
  48. uint64_t current_usec();
  49. int main( int argc, char* argv[] )
  50. {
  51.     if (argc != 2 && argc != 3)
  52.     {
  53.         fprintf(stderr, "Usage:%s test_count rehash\n", argv[0]);
  54.         fprintf(stderr, "For example:%s 10000 rehash\n", argv[0]);
  55.         return -1;
  56.     }
  57.     size_t count = atoi(argv[1]);
  58.     bool rehash = false;
  59.     if (argc == 3)
  60.     {
  61.         rehash = true;
  62.     }
  63.     string_map smap;
  64.     string_hash_map shash_map;
  65.     string_unordered_map sunordered_map;
  66.     if (rehash)
  67.     {
  68.         sunordered_map.rehash(count);
  69.     }
  70.     string_list slist;
  71.     fill_list(slist, count);
  72.     uint64_t start = 0;
  73.     uint64_t end = 0;
  74.     uint64_t map_insert_us = 0;
  75.     uint64_t hash_map_insert_us = 0;
  76.     uint64_t unordered_map_insert_us = 0;
  77.     uint64_t map_traverse_us = 0;
  78.     uint64_t hash_map_traverse_us = 0;
  79.     uint64_t unordered_map_traverse_us = 0;
  80.     uint64_t map_find_us = 0;
  81.     uint64_t hash_map_find_us = 0;
  82.     uint64_t unordered_map_find_us = 0;
  83.     uint64_t map_delete_us = 0;
  84.     uint64_t hash_map_delete_us = 0;
  85.     uint64_t unordered_map_delete_us = 0;
  86.     // Insert test
  87.     {//{{{
  88.         string_list::iterator it(slist.begin());
  89.         string_list::iterator ite(slist.end());
  90.         //map insert
  91.         start = current_usec();
  92.         for (int i = 0; it != ite; ++it, ++i)
  93.         {
  94.             smap[*it] = i;
  95.         }
  96.         end = current_usec();
  97.         map_insert_us = end - start;
  98.         //hash_map insert
  99.         it = slist.begin();
  100.         start = current_usec();
  101.         for (int i = 0; it != ite; ++it, ++i)
  102.         {
  103.             shash_map[*it] = i;
  104.         }
  105.         end = current_usec();
  106.         hash_map_insert_us = end - start;
  107.         //unordered_map insert
  108.         it = slist.begin();
  109.         start = current_usec();
  110.         for (int i = 0; it != ite; ++it, ++i)
  111.         {
  112.             shash_map[*it] = i;
  113.         }
  114.         end = current_usec();
  115.         unordered_map_insert_us = end - start;
  116.     }//}}}
  117.     // Traverse test
  118.     {//{{{
  119.         //map traverse 
  120.         {
  121.             string_map::iterator it(smap.begin());
  122.             string_map::iterator ite(smap.end());
  123.             start = current_usec();
  124.             for (int i = 0; it != ite; ++it)
  125.             {
  126.                 i++;
  127.             }
  128.             end = current_usec();
  129.             map_traverse_us = end - start;
  130.         }
  131.         //hash_map traverse 
  132.         {
  133.             string_hash_map::iterator it(shash_map.begin());
  134.             string_hash_map::iterator ite(shash_map.end());
  135.             start = current_usec();
  136.             for (int i = 0; it != ite; ++it)
  137.             {
  138.                 i++;
  139.             }
  140.             end = current_usec();
  141.             hash_map_traverse_us = end - start;
  142.         }
  143.         //unordered_map traverse 
  144.         {
  145.             string_unordered_map::iterator it(sunordered_map.begin());
  146.             string_unordered_map::iterator ite(sunordered_map.end());
  147.             start = current_usec();
  148.             for (int i = 0; it != ite; ++it)
  149.             {
  150.                 i++;
  151.             }
  152.             end = current_usec();
  153.             unordered_map_traverse_us = end - start;
  154.         }
  155.     }//}}}
  156.     // Find test
  157.     {//{{{
  158.         string_list::iterator it(slist.begin());
  159.         string_list::iterator ite(slist.end());
  160.         //map find
  161.         start = current_usec();
  162.         for (int i = 0; it != ite; ++it, ++i)
  163.         {
  164.             smap[*it] = i;
  165.         }
  166.         end = current_usec();
  167.         map_find_us = end - start;
  168.         //hash_map find
  169.         it = slist.begin();
  170.         start = current_usec();
  171.         for (int i = 0; it != ite; ++it, ++i)
  172.         {
  173.             shash_map[*it] = i;
  174.         }
  175.         end = current_usec();
  176.         hash_map_find_us = end - start;
  177.         //unordered_map find
  178.         it = slist.begin();
  179.         start = current_usec();
  180.         for (int i = 0; it != ite; ++it, ++i)
  181.         {
  182.             shash_map[*it] = i;
  183.         }
  184.         end = current_usec();
  185.         unordered_map_find_us = end - start;
  186.     }//}}}
  187.     // Delete test
  188.     {//{{{
  189.         string_list::iterator it(slist.begin());
  190.         string_list::iterator ite(slist.end());
  191.         //map delete
  192.         start = current_usec();
  193.         for (int i = 0; it != ite; ++it, ++i)
  194.         {
  195.             smap.erase(*it);
  196.         }
  197.         end = current_usec();
  198.         map_delete_us = end - start;
  199.         //hash_map delete
  200.         it = slist.begin();
  201.         start = current_usec();
  202.         for (int i = 0; it != ite; ++it, ++i)
  203.         {
  204.             shash_map.erase(*it);
  205.         }
  206.         end = current_usec();
  207.         hash_map_delete_us = end - start;
  208.         //unordered_map delete
  209.         it = slist.begin();
  210.         start = current_usec();
  211.         for (int i = 0; it != ite; ++it, ++i)
  212.         {
  213.             shash_map.erase(*it);
  214.         }
  215.         end = current_usec();
  216.         unordered_map_delete_us = end - start;
  217.     }//}}}
  218.     //stat output
  219.     std::cout << " insert, count " << count << std::endl;
  220.     std::cout << " std::map " << map_insert_us << " us\n";
  221.     std::cout << " std::ext/hash_map " << hash_map_insert_us << " us\n";
  222.     std::cout << "std::tr1::unordered_map " << unordered_map_insert_us << " us\n";
  223.     std::cout << "\n";
  224.     std::cout << " traverse, count " << count << std::endl;
  225.     std::cout << " std::map " << map_traverse_us << " us\n";
  226.     std::cout << " std::ext/hash_map " << hash_map_traverse_us << " us\n";
  227.     std::cout << "std::tr1::unordered_map " << unordered_map_traverse_us << " us\n";
  228.     std::cout << "\n";
  229.     std::cout << " find, count " << count << std::endl;
  230.     std::cout << " std::map " << map_find_us << " us\n";
  231.     std::cout << " std::ext/hash_map " << hash_map_find_us << " us\n";
  232.     std::cout << "std::tr1::unordered_map " << unordered_map_find_us << " us\n";
  233.     std::cout << "\n";
  234.     std::cout << " delete, count " << count << std::endl;
  235.     std::cout << " std::map " << map_delete_us << " us\n";
  236.     std::cout << " std::ext/hash_map " << hash_map_delete_us << " us\n";
  237.     std::cout << "std::tr1::unordered_map " << unordered_map_delete_us << " us\n";
  238.      
  239.     return 0;
  240. }
  241. void fill_list(string_list& slist, size_t count)
  242. {
  243.     for (size_t i = 0; i < count; ++i)
  244.     {
  245.         std::ostringstream oss;
  246.         oss << i;
  247.         //slist.push_back(MD5::getHexMD5(oss.str().c_str(), oss.str().length()));
  248.         slist.push_back(oss.str());
  249.     }
  250. }
  251. uint64_t current_usec()
  252. {
  253.     struct timeval tv;
  254.     gettimeofday( &tv, NULL );
  255.     return tv.tv_sec * 1000 * 1000 + tv.tv_usec;
  256. }
分享到:
评论

相关推荐

    linux hash_map

    Linux下的`hash_map`是一种基于哈希表的数据结构,它提供了高效的键值对存储功能。与`map`不同,`hash_map`...在C++11及以后的版本中,推荐使用`std::unordered_map`,它是标准库的一部分,具有更好的跨平台性和性能。

    C++中的哈希容器unordered_map使用示例

    但是对于hash表来说,由于无法避免re-hash所带来的性能问题,即使大多数情况下hash表的性能非常好,但是re-hash所带来的不稳定性在当时是不能容忍的。 不过由于hash表的性能优势,它的使用面还是很广的,于是第三方...

    Hash_map 实现源码

    在C++中,STL(Standard Template Library)提供了一个名为`std::unordered_map`的容器,它是基于哈希表实现的。然而,如果你想要深入理解哈希映射的工作原理,或者需要自定义哈希函数和冲突解决策略,那么编写自己...

    检索速度最快的哈希算法和map

    影响程序性能的瓶颈也往往是map的性能。尤其在大数据情况下,以及业务关联紧密而无法实现数据分发和并行处理的情况。map的性能就成了最关键的技术。 比如:ip表、mac表,电话号码表、身份证号码表的查询、等等。 ...

    dense_hash_map:STD的简单替代

    jg :: dense_hash_map 一个简单的std::unordered_map替代品,具有更好的性能,但失去了稳定的寻址方式,这是一种折衷方案。 在此处查看此哈希图的详细说明: : 生成状态: 特拉维斯(Travis):

    robin-hood-hashing:基于C ++ 11141720的基于robin hood哈希的快速且内存高效的哈希表

    robin_hood::unordered_map和robin_hood::unordered_set是std::unordered_map / std::unordered_set独立于平台的替代品,对于实际的用例而言,它既更快,更高效。 安装及使用 直接纳入 将添加到您的C ++项目。 ...

    哈希映射 hash map

    此外,`hash_map`的性能还依赖于桶的数量,桶的数量越大,每个桶中元素的平均数量就越少,冲突的可能性也就越小,查找效率越高。在实际使用中,可以通过调整桶的数量来优化性能。 使用`hash_map`的示例代码如下: ...

    All hash ids_hash_Table_

    例如,Java中的HashMap和C++中的std::unordered_map都是常见的哈希表实现。这些实现通常会提供线性时间复杂度的插入、删除和查找操作,但在最坏情况下,如所有键都哈希到同一个位置,性能可能会退化到O(n)。 总的来...

    细讲c++ 各种STL容器的应用场合及性能

    c++ std stl各容器的应用场合及性能 map hash_map unordered_map multimap list forward_list vector set hash_set multiset unsorted_set queue deque priority_queue

    linked_hash:L链式哈希[LRU]用于C ++的快速,仅标头,跨平台和类似STL的linked_hash_map和linked_hash_set。 (在leetcode上击败100%的提交)

    这个数据结构类似于C++标准库中的`std::unordered_map`,但它的设计目标是提供更快的性能和更好的内存管理。`linked_hash_map`采用链式哈希表,每个桶内部通过双向链表连接元素,使得在哈希冲突时,可以通过链表顺序...

    stl_code.rar_STL vector_hash_stl set code_vector_vector stl

    - `hash`在C++中通常是指`unordered_map`或`unordered_set`容器,它们使用哈希表来存储元素,提供快速的查找和插入操作。 - 哈希表通过计算元素的哈希值来确定其存储位置,理想情况下,哈希函数可以将不同元素均匀...

    unordered-map的使用方法.rar

    虽然`unordered_map`在平均情况下提供了高效的查找,但在最坏的情况下(所有键哈希到同一个位置),性能会退化到O(n)。此外,由于内存分配和哈希碰撞,`unordered_map`可能比`map`占用更多内存。 **适用场景** 当...

    unordered_map和unordered_set的模拟实现

    unordered_map和unordered_set的模拟实现 (一)哈希表的特性及概念 定义: 哈希表(Hash table,也叫散列表),是根据关键字值(key,value)直接进行访问的数据结构。也就是说,它通过把关键字映射到表中一个位置来...

    Hash_Windows编程_源码

    例如,使用C++标准库中的`std::unordered_map`可以创建一个哈希表,然后自定义哈希函数和冲突解决策略来实现二次探测。C#中,可以利用`System.Collections.Generic.Dictionary, TValue&gt;`,并为其提供自定义的哈希...

    LRU.rar_LRU

    unordered_map, Node*&gt; hash_map; list*&gt; list_; public: LRUCache(int capacity) : capacity_(capacity) {} int get(int key) { if (hash_map.find(key) != hash_map.end()) { moveToHead(hash_map[key]); ...

    基于C语言实现unordered-map的增删改查(源码)

    实现了创建哈希表的函数 createHashtable,哈希函数 hash,插入键值对的函数 insert,查找键对应值的函数 get,删除指定键的节点的函数 erase,以及打印哈希表的函数 printHashtable。 在 main 函数中进行了简单的...

    parallel-hashmap:一系列仅标头,非常快速且对内存友好的hashmap和btree容器

    替换std::unordered_map , std::unordered_set , std::map和std::set 需要具有C ++ 11支持的编译器,提供了C ++ 14和C ++ 17 API(例如try_emplace ) 非常高效,比编译器的无序映射/集合或Boost或显着更快 ...

    STL.rar_hash stl_stl 封装_搜索树

    哈希表是一种能够快速查找的数据结构,STL通过`&lt;unordered_set&gt;`和`&lt;unordered_map&gt;`这两个容器来实现。哈希表基于哈希函数,可以实现平均时间复杂度为O(1)的查找、插入和删除操作。`&lt;unordered_set&gt;`用于存储不...

    哈希表应用C++_STL_hash

    通过`std::hash`模板类的特化或者`std::unordered_set/map`的`hash_function`成员函数进行设置。 - **等价关系**:对于`std::unordered_map`,键的等价关系默认由`==`运算符决定。如果需要自定义,可以提供一个比较...

Global site tag (gtag.js) - Google Analytics