vc下有2个版本的散列表类,hash_map和unordered_map,hash_map位于stdext命名空间,unordered_map在std命名空间(vs2008及其之后的版本可用),官方推荐使用unordered_map,前者是一个旧的非标版本。

2者使用起来很类似,但构造函数有明显不同。 在使用int之类的值类型作为key的情况下,后几个参数可以使用默认值,无需提供hash function和compare function。但如果需要特殊类型作为散列键值的情况用起来就麻烦很多,比如用字符串string作为散列键值(但如果include了<string>也是无需提供hash function和compare function,很方便)。

template<
    class Key,
    class Ty,
    class Hash = std::hash<Key>,
    class Pred = std::equal_to<Key>,
    class Alloc = std::allocator<std::pair<const Key, Ty> > >
    class unordered_map; template <
   class Key, 
   class Type, 
   class Traits=hash_compare<Key, less<Key> >, 
   class Allocator=allocator<pair <const Key, Type> > >
   class hash_map;  

散列表类有几个概念搞清楚后才能很好的理解这2个构造函数。key键值、value实值、hash值是哈希表最基本的概念,在存储value值的时候,散列表需要将key值转换为hash值(hash值会被用来当做数组下标使用),其类型为无符号整形。key值 --> hash值的映射函数就是hash函数,vc为一些类型的key提供了默认的hash函数,比如int和string。映射函数并不保证key与hash值的映射关系是一一对应的,可能出现多个key值映射到一个hash值的情况。此时我们需要比较函数来解决冲突,用来区分相同hash值下的不同key值。

回到上面的2个构造函数,unordered_map是比较容易理解的,第三个入参【class Hash = std::hash<Key>】,它所需要的类型其实是个函数对象,用来完成散列映射。默认使用了名为hash的函数对象。第四个参数【class Pred = std::equal_to<Key>】,所需要的类型也是函数对象,用来完成hash值冲突后的key值的比较。对这2个参数我们也可以使用自定义的函数对象,比如下面(假设key的类型为int)。另外,string类型比较特殊,后面另说。

struct hashMy
{
    size_t operator()(int _Val) const{return _Val%;}
}; struct equalMy
{    // functor for operator==
    bool operator()(const int _Left, const int _Right) const
    {    // apply operator== to operands
        return (_Left == _Right);
    }
}; std::unordered_map<int,int,hashMy,equalMy> s3;  

而hash_map类的构造函数则是由第三个入参完成hash函数和比较函数2个功能。其默认的函数对象的定义如下

template<class Key, class Traits = less<Key> >
   class hash_compare
   {
   Traits comp;
public:
   const size_t bucket_size = ;
   const size_t min_buckets = ;
   hash_compare( );
   hash_compare( Traits pred );
   size_t operator( )( const Key& _Key ) const;
   bool operator( )( 
      const Key& _Key1,
      const Key& _Key2
   ) const;
   };

注意这个类没有使用equal_to来做hash值冲突后的key值的比较,而是默认使用less函数。据说这是为了提高冲突后的查找效率,当需要判断等于的时候通过!(a < b) && !(b < a)来实现.....自定义的方式如下,假设key是int型。

class hash_compare_my
{
public:
    enum
    { 
        bucket_size = ,
        min_buckets = 
    };
   
    size_t operator( )( const int& _Key ) const{return _Key%;}
    bool operator( )( const int& _Key1,const int& _Key2 ) const
    {
        return (_Key1 < _Key2);
    }
}; stdext::hash_map<int,int,hash_compare_my> t;  

平时经常需要用到string作为key的情况,在不include<string>的情况下,unordered_map会编译失败,我们需要提供自定义的string比较函数,string的hash函数可以复用库中提供的string hash函数。

注意,有include<string> 的情况下不需要提供自定义的hash函数和比较函数。

struct equal_s
{
    bool operator()(const std::string& s1,const std::string& s2)const
    {
        return s1.compare(s2) == ;
    }
};
struct less_s  
{  
    bool operator ()(const std::string & str1, const std::string & str2) const  
    {  
        return str1.compare(str2) < ;  
    }  
}; 
std::unordered_map<std::string,int,std::hash<std::string>,equal_s> s;
stdext::hash_map<std::string,int,stdext::hash_compare<std::string,less_s> > s1;

最后,散列表的插入函数insert有多个重载版本,如果遇到插入的key已经存在则插入操作失败,注意批量插入的重载版本不会显式提示失败。

template<class InputIterator>
    void insert(
        InputIterator _First,
        InputIterator _Last
); pair <iterator, bool> insert(
    const value_type& _Val
);

VC散列表的更多相关文章

  1. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  2. HashTable(散列表)

    最近都在研究数据结构,关于hashtable,或者叫做散列表,过去一直不了解是什么东西,现在终于明白了. 所谓hashtable,就是某组key,通过某个关系(函数),得到一个与之对应的映射值(在计算 ...

  3. &11,散列表

    #1,是什么? 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个 ...

  4. [转载] 散列表(Hash Table)从理论到实用(上)

    转载自:白话算法(6) 散列表(Hash Table)从理论到实用(上) 处理实际问题的一般数学方法是,首先提炼出问题的本质元素,然后把它看作一个比现实无限宽广的可能性系统,这个系统中的实质关系可以通 ...

  5. [转载] 散列表(Hash Table)从理论到实用(中)

    转载自:白话算法(6) 散列表(Hash Table)从理论到实用(中) 不用链接法,还有别的方法能处理碰撞吗?扪心自问,我不敢问这个问题.链接法如此的自然.直接,以至于我不敢相信还有别的(甚至是更好 ...

  6. [转载] 散列表(Hash Table) 从理论到实用(下)

    转载自: 白话算法(6) 散列表(Hash Table) 从理论到实用(下) [澈丹,我想要个钻戒.][小北,等等吧,等我再修行两年,你把我烧了,舍利子比钻戒值钱.] ——自扯自蛋 无论开发一个程序还 ...

  7. Java学习笔记(二十)——Java 散列表_算法内容

    [前面的话] 周末,本来打算找人去玩,结果没找到,所以我只好有学习了. 为什么会学习散列表,因为要使用HashMap?因为在做项目的时候,在服务器和客户端需要传输DTO,而传输的属性是动态增加的,所以 ...

  8. [Linux] Linux进程PID散列表

    linux系统中每个进程由一个进程id标识,在内核中对应一个task_struct结构的进程描述符,系统中所有进程的task_struct通过链表链接在一起,在内核中,经常需要通过进程id来获取进程描 ...

  9. JavaScript数据结构——集合、字典和散列表

    集合.字典和散列表都可以存储不重复的值. 在集合中,我们感兴趣的是每个值本身,并把它当作主要元素.在字典和散列表中,我们用 [键,值] 的形式来存储数据. 集合(Set 类):[值,值]对,是一组由无 ...

随机推荐

  1. go语言的排序、结构体排序

    原文:https://studygolang.com/articles/1598 晚上准备动手写点 go 的程序的时候,想起 go 如何排序的问题.排序 sort 是个基本的操作,当然搜索 searc ...

  2. Exception has been thrown by the target of an invocation 网站报错

    最近因为要做一个启动器,在使用WPF做UI的时候,发现有错误如下: 错误 1 未知的生成错误"此实现不是 Windows 平台 FIPS 验证的加密算法的一部分. 行 8 位置 3.&quo ...

  3. 阿里云上如何利用war包安装jenkins

    一. 前提条件:已安装jdk和tomcat 如何安装,请参考<如何在阿里云上部署war包到tomcat服务器> 二. 下载war包 下载地址:http://mirrors.jenkins- ...

  4. 接口测试工具---postman下载地址

    接口测试工具---postman下载地址: https://app.getpostman.com/app/download/win64?_ga=2.3555895.622696496.15081214 ...

  5. golang采坑记 一(http与json)

    http服务端在把json串写入http.ResponseWriter对象的时候我们常用的方式如下: //方法一: func ...(w http.ResponseWriter, r *http.Re ...

  6. IOS-界面传值

    第二个视图控制器如何获取第一个视图控制器的部分信息 例如 :第二个界面中的lable显示第一个界面textField中的文本 这就需要用到属性传值.block传值 那么第一个视图控制器如何获的第二个视 ...

  7. Audio/Movie/Image

    Audio 1. 引入AVFoundation 库,此库用于处理音频的播放. > 使用AVAudioPlayer 播放音频,此类只能播放本地音频文件.对于流媒体(边下边播)的播放使用第三方框架实 ...

  8. Android中从SD卡中读取歌曲

    先看看我的效果图吧 Activity类 private TextView nameTextView; private SeekBar seekBar; private ListView listVie ...

  9. Could not find a valid gem 'rails' (>= 0), here is why

    很长一段时间之前 Ruby Rails入门--windows下搭建Ruby Rails Web开发环境 ,由于后来将Ruby的安装文件从 C 盘移动到了 D 盘,也修改了 Path 环境变量,ruby ...

  10. golang日期转字符串,仿照C#中的日期格式结构体

    1.日期格式集合.日期转字符串方法 package util import ( "strings" "time" ) //日期格式:模仿java中的结构体 ty ...