本文只介绍我们在C++中如何使用Hash这种数据结构达到我们编程的目的,有关Hash的概念和实现不做详谈。

C++11新增了一类散列容器包括unordered_set, unordered_map, unordered_multiset, unordered_multimap, 即之前熟悉的hash_set, hash_map等。

这类容器底层以哈希表实现之,通过unordered_map介绍下这类容器的使用。

unordered_map 是一个模板类,需要我们提供5个魔板参数。依次为:key值的类型, value值的类型,hash函数, 等价函数, 容器分配器。其中后三个有默认参数,那我们是不是只需要提供前2个模板参数就可以使用了呢? 不一定。当我们使用的key为内置类型时(如int, double, float, string等),后面三个默认模板参数在STL内有其特化版本,故可以直接进行使用。可一旦你的类为自定义类型, 其中的hash和equal就得由你自己提供。其实也不难理解, 假设你的对象是一块石头,石头怎么进行hash, 石头怎么怎么比大小呢?编译器当然不知道,这就需要你告诉编译器。下面我们对这2种情况分别举例说明。

(一)、当key为内置类型:

unordered_map<string, int> m_map;

当key为内置类型, 仅需提供key与value的类型便可运用。 其中hash<string> 与 equal <int> 均有特化版本,分配器对整个容器进行内存管理,这三个参数均为默认参数。

(二)、当key为自定义类型:

比如我们简单定义一个package类,里面仅有名字,电话2项数据。

class package
{
public:
string getName() const { return name; }
long long getPhone() const { return phone; } package(string m_name = , long long m_pNum = ); bool operator== (const package& p) const
{ return name == p.name &&
phone == p.phone;
}
private:
string name;
long long phone;
};

然后将原生hash包装使用下:

namespace std
{
template<>
struct hash<package>
{
size_t operator() (const package& s) const noexcept
{
return hash<decltype(s.getName())>()(s.getName()) +
hash<decltype(s.getPhone())>()(s.getPhone());
}
}; // 间接调用原生Hash.
}

或者可以借助借助boost库的hash_value:

 namespace std
{
template<>
struct hash<package>
{
size_t operator() (const package& s) const noexcept
{
auto t = make_tuple(s.getName(), s.getPhone());
size_t value = boost::hash_value(t);
return value; // make_tuple(s.getName(), s.getPhone()) 等价于 tuple<string, long long>()(s.getName(), s.getPhone())
}
}; // 间接调用原生Hash.
}

当我们把Hash函数(package的特化版本)和 等价函数 (操作符==重载)提供后, 便可使用自定义版本的unordered_map了:

unordered_map<package, int> m_map;

下面给出测试代码:

测试环境: VS2017

#include <iostream>
#include <unordered_map>
#include <string>
#include <algorithm>
//#include <boost/functional/hash.hpp> // 根据安装路径选择hash.hpp
#include <tuple> using namespace std; class package
{
public:
string getName() const { return name; }
long long getPhone() const { return phone; } package(string m_name = , long long m_pNum = ); bool operator== (const package& p) const
{ return name == p.name &&
phone == p.phone;
} private:
string name;
long long phone;
}; package::package(string m_name, long long m_pNum)
: name(m_name), phone(m_pNum) { } namespace std
{
template<>
struct hash<package>
{
size_t operator() (const package& s) const noexcept
{
return hash<decltype(s.getName())>()(s.getName()) +
hash<decltype(s.getPhone())>()(s.getPhone()); //auto t = make_tuple(s.getName(), s.getPhone());
//size_t value = boost::hash_value(t);
//return value; // make_tuple(s.getName(), s.getPhone()) 等价于 tuple<string, long long>()(s.getName(), s.getPhone())
}
}; // 间接调用原生Hash.
} int main()
{
unordered_map<package, int> m_map; package p1{ "Wang", };
package p2{ "Li", };
package p3{ "Zhang", };
package p4{ "Zhou", };
package p5{ "Wang", };
package p6{ "Wang", }; m_map[p1]++;
m_map[p2]++;
m_map[p3]++;
m_map[p4]++;
m_map[p5]++;
m_map[p6]++; cout << m_map.bucket(p1) << " ";
cout << m_map.bucket(p2) << " ";
cout << m_map.bucket(p3) << " ";
cout << m_map.bucket(p4) << " ";
cout << m_map.bucket(p5) << " ";
cout << m_map.bucket(p6) << " " << endl; return ;
}

关于C++中Hash的应用的更多相关文章

  1. IOS9.0中hash值的bug与解决方案

    事件起因 事情是这样的:产品上线发布,突然出现了问题.运营Gg过来反应,当场给露珠演示,运营同事的手机是iphone,bug确实是存在的.奇怪的是露珠用了其他iphone手机(借别人的,露珠的是吊死安 ...

  2. URL中 # (hash)的含义

    url中#(hash)的含义 hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分) 1."#"代表网页中的一个位置.其右面的字符,就是该位置的 ...

  3. 关于HashMap中hash()函数的思考

    关于HashMap中hash()函数的思考 JDK7中hash函数的实现   static int hash(int h) { h ^= (h >>> 20) ^ (h >&g ...

  4. Vue-router 中hash模式和history模式的区别

    实际上存在三种模式: Hash: 使用URL的hash值来作为路由.支持所有浏览器. History: 以来HTML5 History API 和服务器配置.参考官网中HTML5 History模式 ...

  5. Vue中hash模式和history模式的区别

    vue-router 中hash模式和history模式. 在vue的路由配置中有mode选项,最直观的区别就是在hash模式下的地址栏里的URL夹杂着‘#’号 ,而history模式下没有.vue默 ...

  6. Webpack中hash与chunkhash的区别,以及js与css的hash指纹解耦方案

    文件的hash指纹通常作为前端静态资源实现增量更新的方案之一,Webpack是目前最流行的开源编译工具之一,其强大的功能也带来很多坑(当然,大部分麻烦其实都可以在官方文档中找到答案). 比如,在Web ...

  7. Java中hashCode()方法以及HashMap()中hash()方法

    Java的Object类中有一个hashCode()方法: public final native Class<?> getClass(); public native int hashC ...

  8. ruby中Hash排序

    当values都是整形时,按照Hash的Values排序: h = {'a'=>1,'b'=>2,'c'=>5,'d'=>4} h.sort {|a,b| a[1]<=& ...

  9. 10g中HASH GROUP BY引起的临时表空间不足

    原本在9i上可以顺利完成的CTAS脚本,迁移到10g后运行总是报“ORA-1652: unable to extend temp segment by 128 in tablespace TS_HQY ...

  10. Redis中hash表中的field的value自增可以用hincrby

    Redis HINCRBY命令用于增加存储在字段中存储由增量键哈希的数量.如果键不存在,新的key被哈希创建.如果字段不存在,值被设置为0之前进行操作. 回复整数,字段的增值操作后的值. redis ...

随机推荐

  1. dedecms自定义模块流程

    dedecms的自定义模块   1.在dedecms主目录下创建一个模块目录 2.在模块目录下创建如下目录 1 2 3 4 5 6 7 8 9 10 网站根目录/     |-自定义模块        ...

  2. iOS进阶之UDP代理鉴权过程

    上一篇介绍的是TCP代理的鉴权过程,这篇将介绍UDP代理的大致鉴权过程. 在UDP鉴权过程中,有几点是需要注意的.首先,UDP是一种无连接协议,不需要连接,使用广播的方式:其次,为了通过鉴权,所以需要 ...

  3. Java8增强的包装类

    为了解决8中基本数据类型的变量不能当成Object 类型变量使用的问题,Java提供了包装类的概念,为8种基本数据类型分别定义了相应的引用类型,并称为基本数据类型的包装类. JDK 1.5提供了自动装 ...

  4. Vagrant Box下载缓慢解决方法

    box 搜索页面:https://atlas.hashicorp.com/boxes/search example:homestead 1,选中box和版本,先根据提示安装 2,获取box下载地址,采 ...

  5. day17

    包什么是包 包的本质是文件夹为什么使用包 函数可以使得同一个文件中代码结构更清晰 木块(py文件)是以文件形式来组织代码结构 如果文件越来越多管理起来也不方便,所以需要使用文件夹来管理.从文件夹级别来 ...

  6. python进阶(一)

    一.调试Debugging应用 (1)命令行内运行 $ python -m pdb my_script.py 这会触发debugger在脚本第⼀⾏指令处停⽌执⾏.这在脚本很短时会很有帮助.你可以通过( ...

  7. linux基础之CentOS7新特性

    CentOS7开机启动顺序: POST --> Boot Sequence --> Bootloader --> kernel + initramfs(initrd) --> ...

  8. BZOJ 4259 残缺的字符串

    思路 同样是FFT进行字符串匹配 只不过两个都有通配符 匹配函数再乘一个\(A_i\)即可 代码 #include <cstdio> #include <algorithm> ...

  9. Vue-admin工作整理(三):路由

    1.router-link和router-view组件 router-link组件实际上是封装了一个a标签(链接标签),里面有一个重要属性:“to”,它的值是一个路径,其路径对应的渲染组件,要在路由列 ...

  10. git删除远程分支,删除本地分支

    远程 # git push origin --delete duck - [deleted] duck 本地 # git branch -d duck 已删除分支 duck(曾为 dda11b8). ...