详细解说hash_map

cadence virtuoso 激励信号源 vpulse,vpwl,vsin,vsource信号源介绍 阅读详情
几句话道出map和hash_map的区别

1. STL map is an associative array where keys are stored in sorted order using balanced trees. While hash_map is a hashed associated container, where keys are not stored in an ordered way. Key, value pair is stored using a hashed function.
2. Insertion and lookup takes Ologn time in map, Also performance would degrade as the key size increases. Mainly balance operations on large key ranges would kill performance. while lookup is very efficient O(1) in hash_map.
3. Map is useful where you want to store keys in sorted order, hash_map is used where keys order is not important and lookup is very efficient.
4. One more difference is map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators.
Performance would mostly be o(lgn) due to the implementation of a balanced tree. 
For Map custom objects you would need at the minimum the following operators to store data in a map "<" ">" "==" and of course the other stuff for deep copy.

原文地址:http://stlchina.huhoo.net/twiki/bin/view.pl/Main/STLDetailHashMap

      • 0 为什么需要hash_map
      • 1 数据结构:hash_map原理
      • 2 hash_map 使用
        • 2.1 一个简单实例
        • 2.2 hash_map 的hash函数
        • 2.3 hash_map 的比较函数
        • 2.4 hash_map 函数
      • 3 相关hash容器
      • 4 其他
        • 4.1 hash_map和map的区别在哪里?
        • 4.2 什么时候需要用hash_map,什么时候需要用map?
        • 4.3 如何在hash_map中加入自己定义的类型?
        • 4.4 如何用hash_map替换程序中已有的map容器?
        • 4.5 为什么hash_map不是标准的?
        • 4.6 有学习使用hash_map的建议吗?
      • 5 参考文章:

    条条大路通罗马,为什么你不随便选一条?

    0 为什么需要hash_map
    用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能。例如,我要记录一个人名和相应的存储,而且随时增加,要快速 查找和修改:
    岳不群-华山派掌门人,人称君子剑 张三丰-武当掌门人,太极拳创始人 东方不败-第一高手,葵花宝典 ...

    这些信息如果保存下来并不复杂,但是找起来比较麻烦。例如我要找"张三丰"的信息,最傻的方法就是取得所有的记录,然后按照名字一个一个比较。如果要速度快,就需要把这些记录按照字母顺序排列,然后按照二分法查找。但是增加记录的时候同时需要保持记录有序,因此需要插入排序。考虑到效率,这就需要用到二叉树。讲下去会没完没了,如果你使用STL 的map容器,你可以非常方便的实现这个功能,而不用关心其细节。关于map的数据结构细节,感兴趣的朋友可以参看学习STL map, STL set之数据结构基础。 看看map的实现:

    #include <map>
    #include <string>
    using namespace std;
    ...
    map<string, string> namemap;
     
    //增加。。。 namemap["岳不群"]="华山派掌门人,人称君子剑";
    namemap["张三丰"]="武当掌门人,太极拳创始人";
    namemap["东方不败"]="第一高手,葵花宝典";
    ... //查找。。
    if(namemap.find("岳不群") != namemap.end()){
    ...
    }

    不觉得用起来很easy吗?而且效率很高,100万条记录,最多也只要20次的string.compare的比较,就能找到你要找的记录;200万条记 录事,也只要用21次的比较。

    速度永远都满足不了现实的需求。如果有100万条记录,我需要频繁进行搜索时,20次比较也会成为瓶颈,要是能降到一次或者两次比较是否有可能?而且当记 录数到200万的时候也是一次或者两次的比较,是否有可能?而且还需要和map一样的方便使用。

    答案是肯定的。这时你需要has_map. 虽然hash_map目前并没有纳入C++ 标准模板库中,但几乎每个版本的STL都提供了相应的实现。而且应用十分广泛。在正式使用hash_map之前,先看看hash_map的原理。

    1 数据结构:hash_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时需要指定的参数。

    2 hash_map 使用
    2.1 一个简单实例
    不要着急如何把"岳不群"用hash_map表示,我们先看一个简单的例子:随机给你一个ID号和ID号相应的信息,ID号的范围是1~2的31次方。如 何快速保存查找。
    #include <hash_map>
    #include <string>
    using namespace std;
    int main(){
    hash_map<int, string> mymap;
    mymap[9527]="唐伯虎点秋香";
    mymap[1000000]="百万富翁的生活";
    mymap[10000]="白领的工资底线";
    ...
    if(mymap.find(10000) != mymap.end()){
    ...
    }

    够简单,和map使用方法一样。这时你或许会问?hash函数和比较函数呢?不是要指定么?你说对了,但是在你没有指定hash函数和比较函数的时候,你 会有一个缺省的函数,看看hash_map的声明,你会更加明白。下面是SGI STL的声明:

    template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
    class _EqualKey = equal_to<_Key>,
    class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
    class hash_map
    {
    ...
    }

    也就是说,在上例中,有以下等同关系:

    ... hash_map<int, string> mymap;
    //等同于: hash_map<int, string, hash<int>, equal_to<int> > mymap;
     

    Alloc我们就不要取关注太多了(希望深入了解Allocator的朋友可以参看标准库 STL :Allocator能做什么)

    2.2 hash_map 的hash函数
    hash< int>到底是什么样子?看看源码:
    struct hash<int> {
    size_t operator()(int __x) const { return __x; }
    };

    原来是个函数对象。在SGI STL中,提供了以下hash函数:

    struct hash<char*> struct hash<const char*> struct hash<char> struct hash<unsigned char> struct hash<signed char> struct hash<short> struct hash<unsigned short> struct hash<int> struct hash<unsigned int> struct hash<long> struct hash<unsigned long>

    也就是说,如果你的key使用的是以上类型中的一种,你都可以使用缺省的hash函数。当然你自己也可以定义自己的hash函数。对于自定义变量,你只能 如此,例如对于string,就必须自定义hash函数。例如:

    struct str_hash{
    size_t operator()(const string& str) const
    {
    unsigned long __h = 0;
    for (size_t i = 0 ; i < str.size() ; i ++)
    __h = 5*__h + str[i];
    return size_t(__h);
    } }; //如果你希望利用系统定义的字符串hash函数,你可以这样写: struct str_hash{
    size_t operator()(const string& str) const
    {
    return __stl_hash_string(str.c_str());
    } };

    在声明自己的哈希函数时要注意以下几点:

    1. 使用struct,然后重载operator().
    2. 返回是size_t
    3. 参数是你要hash的key的类型。
    4. 函数是const类型的。
    如果这些比较难记,最简单的方法就是照猫画虎,找一个函数改改就是了。

    现在可以对开头的"岳不群"进行哈希化了 smile . 直接替换成下面的声明即可:

    map<string, string> namemap; //改为: hash_map<string, string, str_hash> namemap;

    其他用法都不用边。当然不要忘了吧str_hash的声明以及头文件改为hash_map。

    你或许会问:比较函数呢?别着急,这里就开始介绍hash_map中的比较函数。

    2.3 hash_map 的比较函数
    在map中的比较函数,需要提供less函数。如果没有提供,缺省的也是less< Key> 。在hash_map中,要比较桶内的数据和key是否相等,因此需要的是是否等于的函数:equal_to< Key> 。先看看equal_to的源码:
    //本代码可以从SGI STL //先看看binary_function 函数声明,其实只是定义一些类型而已。 template <class _Arg1, class _Arg2, class _Result> struct binary_function { typedef _Arg1 first_argument_type; typedef _Arg2 second_argument_type; typedef _Result result_type; }; //看看equal_to的定义: template <class _Tp> struct equal_to : public binary_function<_Tp,_Tp,bool> { bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; } };

    如果你使用一个自定义的数据类型,如struct mystruct, 或者const char* 的字符串,如何使用比较函数?使用比较函数,有两种方法. 第一种是:重载==操作符,利用equal_to;看看下面的例子:

    struct mystruct{ int iID; int len; bool operator==(const mystruct & my) const{ return (iID==my.iID) && (len==my.len) ; } };

    这样,就可以使用equal_to< mystruct>作为比较函数了。另一种方法就是使用函数对象。自定义一个比较函数体:

    struct compare_str{ bool operator()(const char* p1, const char*p2) const{ return strcmp(p1,p2)==0; } };

    有了compare_str,就可以使用hash_map了。

    typedef hash_map<const char*, string, hash<const char*>, compare_str> StrIntMap;
    StrIntMap namemap;
    namemap["岳不群"]="华山派掌门人,人称君子剑";
    namemap["张三丰"]="武当掌门人,太极拳创始人";
    namemap["东方不败"]="第一高手,葵花宝典";
     
    2.4 hash_map 函数
    hash_map的函数和map的函数差不多。具体函数的参数和解释,请参看: STL 编程手册:Hash_map,这里主要介绍几个常用函数。
    1. hash_map(size_type n) 如果讲究效率,这个参数是必须要设置的。n 主要用来设置hash_map 容器中hash桶的个数。桶个数越多,hash函数发生冲突的概率就越小,重新申请内存的概率就越小。n越大,效率越高,但是内存消耗也越大。
    2. const_iterator find(const key_type& k) const. 用查找,输入为键值,返回为迭代器。
    3. data_type& operator[](const key_type& k) . 这是我最常用的一个函数。因为其特别方便,可像使用数组一样使用。不过需要注意的是,当你使用[key ]操作符时,如果容器中没有key元素,这就相当于自动增加了一个key元素。因此当你只是想知道容器中是否有key元素时,你可以使用find。如果你希望插入该元素时,你可以直接使用[]操作符。
    4. insert 函数。在容器中不包含key值时,insert函数和[]操作符的功能差不多。但是当容器中元素越来越多,每个桶中的元素会增加,为了保证效率,hash_map会自动申请更大的内存,以生成更多的桶。因此在insert以后,以前的iterator有可能是不可用的。
    5. erase 函数。在insert的过程中,当每个桶的元素太多时,hash_map可能会自动扩充容器的内存。但在sgi stl中是erase并不自动回收内存。因此你调用erase后,其他元素的iterator还是可用的。
    3 相关hash容器
    hash 容器除了hash_map之外,还有hash_set, hash_multimap, has_multiset, 这些容器使用起来和set, multimap, multiset的区别与hash_map和map的区别一样,我想不需要我一一细说了吧。
    4 其他
    这里列几个常见问题,应该对你理解和使用hash_map比较有帮助。
    4.1 hash_map和map的区别在哪里?
    • 构造函数。hash_map需要hash函数,等于函数;map只需要比较函数(小于函数).
    • 存储结构。hash_map采用hash表存储,map一般采用红黑树(RB Tree)实现。因此其memory数据结构是不一样的。
    4.2 什么时候需要用hash_map,什么时候需要用map?
    总体来说,hash_map 查找速度会比map快,而且查找速度基本和数据数据量大小,属于常数级别;而map的查找速度是log(n)级别。并不一定常数就比log(n) 小,hash还有hash函数的耗时,明白了吧,如果你考虑效率,特别是在元素达到一定数量级时,考虑考虑hash_map。但若你对内存使用特别严格,希望程序尽可能少消耗内存,那么一定要小心,hash_map可能会让你陷入尴尬,特别是当你的hash_map对象特别多时,你就更无法控制了,而且 hash_map的构造速度较慢。

    现在知道如何选择了吗?权衡三个因素: 查找速度, 数据量, 内存使用。

    这里还有个关于hash_map和map的小故事,看看:http://dev.youkuaiyun.com/Develop/article/14/14019.shtm

    4.3 如何在hash_map中加入自己定义的类型?
    你只要做两件事, 定义hash函数,定义等于比较函数。下面的代码是一个例子:
    -bash-2.05b$ cat my.cpp #include <hash_map> #include <string> #include <iostream> using namespace std; //define the class class ClassA{ public: ClassA(int a):c_a(a){} int getvalue()const { return c_a;} void setvalue(int a){c_a;} private: int c_a; }; //1 define the hash function struct hash_A{ size_t operator()(const class ClassA & A)const{ // return hash<int>(classA.getvalue()); return A.getvalue(); } }; //2 define the equal function struct equal_A{ bool operator()(const class ClassA & a1, const class ClassA & a2)const{ return a1.getvalue() == a2.getvalue(); } }; int main() { hash_map<ClassA, string, hash_A, equal_A> hmap; ClassA a1(12); hmap[a1]="I am 12"; ClassA a2(198877); hmap[a2]="I am 198877"; cout<<hmap[a1]<<endl; cout<<hmap[a2]<<endl; return 0; } -bash-2.05b$ make my c++ -O -pipe -march=pentiumpro my.cpp -o my -bash-2.05b$ ./my I am 12 I am 198877
    4.4如何用hash_map替换程序中已有的map容器?
    这个很容易,但需要你有良好的编程风格。建议你尽量使用typedef来定义你的类型:
    typedef map<Key, Value> KeyMap;

    当你希望使用hash_map来替换的时候,只需要修改:

    typedef hash_map<Key, Value> KeyMap;

    其他的基本不变。当然,你需要注意是否有Key类型的hash函数和比较函数。

    4.5为什么hash_map不是标准的?
    具体为什么不是标准的,我也不清楚,有个解释说在STL加入标准C++之时,hash_map系列当时还没有完全实现,以后应该会成为标准。如果谁知道更合理的解释,也希望告诉我。但我想表达的是,正是因为hash_map不是标准的,所以许多平台上安装了g++编译器,不一定有hash_map的实现。我就遇到了这样的例子。因此在使用这些非标准库的时候,一定要事先测试。另外,如果考虑到平台移植,还是少用为佳。
    4.6 有学习使用hash_map的建议吗?
    hash中文是哈希,也成为散列,听见别人说散列容器不要埋怨自己孤陋寡闻。了解hash系列,你还可以看看这篇文章: effective STL 25: 熟悉非标准散列容器, 另外建议查看源代码。如果还有问题,那么你可以在 STL论坛上提问,会有高手回答你的。
    5 参考文章:
    1. 详细解说 STL 排序(Sort)
    2. 详细解说 STL string
    3. Effective STL 中文版
    4. 论坛讨论:STL 论坛: 详细解说STL hash_map系列
YOLOv10改进,YOLOv10添加DICAM,用于水下图像增强模块,以提高朦胧水下图像的质量、对比度和色偏 在水下环境中,成像设备会出现水浑浊、光衰减、散射和颗粒问题,导致图像质量低、对比度差和彩色图像有偏差。这给使用传统视觉技术进行水下状态监测和检查带来了巨大挑战。近年来,水下图像增强因其在提高当前计算机视觉任务在水下目标检测和分割中的性能方面发挥着关键作用而受到越来越多的关注。由于主要从自然场景构建的现有方法在提高色彩丰富度和分布方面存在性能限制,作者提出了一种新颖的基于深度学习的方法,即 Deep Inception 和 Channel-wise Attention Modules (DICAM),以提高朦 阅读详情

相关推荐

Unity 代码混淆<混淆插件(Obfuscator Pro 3.9.4)>

Unity 代码混淆<混淆插件(Obfuscator Pro 3.9.4)> 插件导入项目 导入后打开OPS/Obfuscator/Obfuscator Pro Settings 打开后可以看到界面如下 可以在上面界面中选择你需要混淆的类,方法,字段,属性,事件,参数。需要混淆的程序集的选择。如果有些程序集混淆后会有问题也可以添加到白名单里不被混淆 根据自己需求取选择 这个界面是是否添加添加随机代码的 如果使用了上面的插件可以使用 插件下载网址:https://download.cs

Xing_Cheng_Yun的博客 5103

关于hover的使用注意

今天写css样式的时候发现一个以前没注意到的问题,a:hover b{}这种方式没有改变b的样式。这种方法在以前产生下拉菜单效果的时候是有用的,但是下面这种情况却失效了。&lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;meta charset="UTF-8"&gt; &lt;title&gt;&lt;/title&gt; &

kk的博客 5561

深入理解HanLP1.x,填平可能遇到的坑

提取指定数量的摘要。自定义词典为什么要单独领出来讲呢?因为在我们的业务开发中,可能分词的效果并不理想,需要定制自己的词库,索引更加常用。例如:小米su7特斯拉modelY比亚042025款6575767670908我们需要分出小米su72025款等词。我们分别看看用字典和不用字典的效果。

static_coder的博客 977

详细解说STL hash_map系列

 详细解说STL hash_map系列收藏 新一篇: 数据库专栏 | 旧一篇: 在使用otl的时候,otl_stream构造函数第一个参数buffer size的使用说明. function StorePage(){d=document;t=d.selection?(d.selection.type!=None?d.selection.createRange().tex

skyremember的专栏 2017

ZedBoard+Vivado(二)——PS + PL实现流水灯

硬件:Zedboard 软件:Vivado2018.2 + Win10 本文参考了http://blog.chinaaet.com/cuter521/p/35978的设计 1 设计 功能:PS + PL流水灯 语言:C 流程:创建工程-&amp;gt;IP Integrator-&amp;gt;综合、实现、生成Bitstream-&amp;gt;SDK 2 流程 2.1 创建工程 跟上一篇步骤完全相同,这里不用添加源文...

q416524389的博客 3695

4D Gaussian Splatting for Real-Time Dynamic Scene Rendering-4DGS阅读笔记

为了实现实时动态场景渲染,同时还能具备较高的训练和存储效率,作者提出了四维高斯溅射(4D-GS)方法,将其作为动态场景的一种整体表示方式,而不是对每个单独的帧应用三维高斯溅射(3D-GS)方法。在 4D-GS 中,提出了一种新颖的显式表示方法,它同时包含三维高斯模型和四维神经体素。受 HexPlane 启发,提出了一种分解的神经体素编码算法,以高效地从四维神经体素构建高斯特征,然后应用一个轻量级多层感知器(MLP)来预测在新时间戳下的高斯变形。

2403_85515624的博客 2343

详细解说STL hash_map

用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能。例如,我要记录一个人名和相应的存储,而且随时增加,要快速查找和修改:岳不群-华山派掌门人,人称君子剑张三丰-武当掌门人,太极拳创始人东方不败-第一高手,葵花宝典... 这些信息如果保存下来并不复杂,但是找起来比较麻烦。例如我要找"张三丰"的信息,最傻的方法就是取得所有的记录,然后按照名字一个一个

jia_xiaoxin的专栏 709

在Qt中集成VTK和PCL:实现数据可视化的完整指南

在现代软件开发中,数据可视化至关重要。将VTK(Visualization Toolkit)和PCL(Point Cloud Library)集成到Qt环境里,能为开发者提供强大的可视化解决方案。本文将深入讲解如何在Qt中读取PCL文件,展示VTK模型和PCL数据,适合想要在Qt项目中实现数据可视化的开发者。

轩宇的博客 917

【转】详细解说 hash_map

<br />0 为什么需要hash_map <br />用过map吧?map提供一个很常用的功能,那就是提供key-value的存储和查找功能。例如,我要记录一个人名和相应的存储,而且随时增加, 要快速查找和修改: 岳不群-华山派掌门人,人称君子剑<br /> 张三丰-武当掌门人,太极拳创始人<br /> 东方不败-第一高手,葵花宝典<br /> ...<br />这些信息如果保存下来并不复杂,但是 找起来比较麻烦。例如我要找"张三丰"的信息,最傻的方法就是取得所有的记录,然后按照名字一个一个比

518

Unity零基础到入门 ☀️| 轻松学会 Unity界面布局和简单实例——入门级!(^_−)☆

入门级Unity知识,一起加油呀!

努力前行,总会成为自己心中的那道光 1万+

基于YOLOv5的空间目标智能监测系统:航天器与太空碎片识别技术实现

做完这个项目,你会发现自己完整走过了“数据采集→标注→模型训练→功能集成→界面开发”的毕设全流程,这不仅是技术能力的证明,更是对“技术守护宇宙安全”这一理念的实践。答辩时,你可以重点讲这几点:系统解决了航天监测的哪些痛点、YOLOv5在太空目标检测中的性能优势、系统未来能怎么优化(比如对接航天监测网络、实现实时轨道预测)。未来,这个系统还能往“更智能”的方向发展:比如结合轨道计算预测碰撞风险、开发移动端APP让天文爱好者参与太空垃圾上报、在航天任务中实现全自动避障决策……想象空间很大。

m0_64661770的博客 111
上一篇: 分词:词性标注北大标准
下一篇: 在 Linux 平台中调试 C/C++ 内存泄漏方法
hover_online
博客等级 码龄25年 8粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值