map,hash_map和unordered_map效率比较
Posted 程序员超时空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了map,hash_map和unordered_map效率比较相关的知识,希望对你有一定的参考价值。
转载地址:https://blog.csdn.net/whizchen/article/details/9286557
原理介绍
map介绍
map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
hash_map介绍
hash_map基于hash table(哈希表)。 哈希表最大的优点,就是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价仅仅是消耗比较多的内存。然而在当前可利用内存越来越多的情况下,用空间换时间的做法是值得的。另外,编码比较容易也是它的特点之一。
其基本原理是:使用一个下标范围比较大的数组来存储元素。可以设计一个函数(哈希函数,也叫做散列函数),使得每个元素的关键字都与一个函数值(即数组下标,hash值)相对应,于是用这个数组单元来存储这个元素;也可以简单的理解为,按照关键字为每一个元素“分类”,然后将这个元素存储在相应“类”所对应的地方,称为桶。
但是,不能够保证每个元素的关键字与函数值是一一对应的,因此极有可能出现对于不同的元素,却计算出了相同的函数值,这样就产生了“冲突”,换句话说,就是把不同的元素分在了相同的“类”之中。 总的来说,“直接定址”与“解决冲突”是哈希表的两大特点。
hash_map,首先分配一大片内存,形成许多桶。是利用hash函数,对key进行映射到不同区域(桶)进行保存。其插入过程是:
1.得到key
2.通过hash函数得到hash值
3.得到桶号(一般都为hash值对桶数求模)
4.存放key和value在桶内。
其取值过程是:
1.得到key
2.通过hash函数得到hash值
3.得到桶号(一般都为hash值对桶数求模)
4.比较桶的内部元素是否与key相等,若都不相等,则没有找到。
5.取出相等的记录的value。
hash_map中直接地址用hash函数生成,解决冲突,用比较函数解决。这里可以看出,如果每个桶内部只有一个元素,那么查找的时候只有一次比较。当许多桶内没有值时,许多查询就会更快了(指查不到的时候).
由此可见,要实现哈希表, 和用户相关的是:hash函数和比较函数。这两个参数刚好是我们在使用hash_map时需要指定的参数。
unordered_map介绍
Unordered maps are associative containers that store elements formed by the combination of a_key value_and a_mapped value_, and which allows for fast retrieval of individual elements based on their keys.
In anunordered_map, the_key value_is generally used to uniquely identify the element, while the_mapped value_is an object with the content associated to this_key_. Types of_key_and_mapped_value may differ.
Internally, the elements in theunordered_mapare not sorted in any particular order with respect to either their_key_or_mapped_values, but organized into_buckets_depending on their hash values to allow for fast access to individual elements directly by their_key values_(with a constant average time complexity on average).
unordered_mapcontainers are faster thanmapcontainers to access individual elements by their_key_, although they are generally less efficient for range iteration through a subset of their elements.
Unordered maps implement the direct access operator (operator[]) which allows for direct access of the_mapped value_using its_key value_as argument.
unordered_map与map的区别
boost::unordered_map, 它与 stl::map的区别就是,stl::map是按照operator<比较判断元素是否相同,以及比较元素的大小,然后选择合适的位置插入到树中。所以,如果对map进行遍历(中序遍历)的话,输出的结果是有序的。顺序就是按照operator< 定义的大小排序。
而boost::unordered_map是计算元素的Hash值,根据Hash值判断元素是否相同。所以,对unordered_map进行遍历,结果是无序的。
用法的区别就是,stl::map 的key需要定义operator< 。 而boost::unordered_map需要定义hash_value函数并且重载operator==。对于内置类型,如string,这些都不用操心。对于自定义的类型做key,就需要自己重载operator< 或者hash_value()了。
最后,说,当不需要结果排好序时,最好用unordered_map。
其实,stl::map对于与java中的TreeMap,而boost::unordered_map对应于java中的HashMap。
测试代码
/**
比较map、hash_map和unordered_map的执行效率以及内存占用情况
**/
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <ext/hash_map>
#include <tr1/unordered_map>
using namespace std;
using namespace __gnu_cxx;
using namespace std::tr1;
#define N 100000000 //分别测试N=100,000、N=1,000,000、N=10,000,000以及N=100,000,000
//分别定义MapKey=map<int,int>、hash_map<int,int>、unordered_map<int,int>
//typedef map<int,int> MapKey; //采用map
//typedef hash_map<int,int> MapKey; //采用hash_map
typedef unordered_map<int,int> MapKey; //采用unordered_map
int GetPidMem(pid_t pid,string& memsize)
char filename[1024];
snprintf(filename,sizeof(filename),"/proc/%d/status",pid);
ifstream fin;
fin.open(filename,ios::in);
if (! fin.is_open())
cout<<"open "<<filename<<" error!"<<endl;
return (-1);
char buf[1024];
char size[100];
char unit[100];
while(fin.getline(buf,sizeof(buf)-1))
if (0 != strncmp(buf,"VmRSS:",6))
continue;
sscanf(buf+6,"%s%s",size,unit);
memsize = string(size)+string(unit);
fin.close();
return 0;
int main(int argc, char *argv[])
struct timeval begin;
struct timeval end;
MapKey MyMap;
gettimeofday(&begin,NULL);
for(int i=0;i<N;++i)
MyMap.insert(make_pair(i,i));
gettimeofday(&end,NULL);
cout<<"insert N="<<N<<",cost="<<end.tv_sec-begin.tv_sec + float(end.tv_usec-begin.tv_usec)/1000000<<" sec"<<endl;
for(int i=0;i<N;++i)
MyMap.find(i);
gettimeofday(&end,NULL);
cout<<"insert and getall N="<<N<<",cost="<<end.tv_sec-begin.tv_sec + float(end.tv_usec-begin.tv_usec)/1000000<<" sec"<<endl;
string memsize;
GetPidMem(getpid(),memsize);
cout<<memsize<<endl;
return 0;
运行结果
记录数N=100000时,结果如下:
Map类型
插入耗时,单位秒
插入加遍历耗时,单位秒
内存占用情况
map
0.110705
0.171859
5,780kB
hash_map
0.079074
0.091751
5,760kB
unordered_map
0.041311
0.050298
5,216kB
记录数N=1000000时,结果如下:
Map类型
插入耗时,单位秒
插入加遍历耗时,单位秒
内存占用情况
map
1.22678
1.95435
47,960kB
hash_map
0.684772
0.814646
44,632kB
unordered_map
0.311155
0.386898
40,604kB
记录数N=10000000时,结果如下:
Map类型
插入耗时,单位秒
插入加遍历耗时,单位秒
内存占用情况
map
14.9517
23.9928
469,844kB
hash_map
5.93318
7.18117
411,904kB
unordered_map
3.64201
4.43355
453,920kB
记录数N=100000000时,结果如下:
Map类型
插入耗时,单位秒
插入加遍历耗时,单位秒
内存占用情况
map
167.941
251.591
4,688,692kB
hash_map
46.3518
57.6972
3,912,632kB
unordered_map
28.359
35.122
4,3012,56kB
结果分析
运行效率方面:unordered_map最高,hash_map其次,而map效率最低
占用内存方面:hash_map内存占用最低,unordered_map其次,而map占用最高
以上是关于map,hash_map和unordered_map效率比较的主要内容,如果未能解决你的问题,请参考以下文章