笔者在读研刚开始的时候,偶尔看面经,有这样一个问题:只用2GB内存在20亿个整数中找到出现次数最多的数,当时的我一脸懵逼,怎么去思考,20亿个数?What The Fuck! 但是,看完今天的文章,你或许就会觉得原来也不过如此啊!其核心就是哈希函数和哈希表的应用!

哈希函数

哈希函数又称为散列函数,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。假设输出值域为S,哈希函数的性质如下:

  1. 典型的哈希函数都有无限的输入值域
  2. 当哈希函数输入一致时,输出必相同
  3. 当哈希函数传入不同的输入值时,返回值可能一样,也可能不一样,由于输入域远大于值域
  4. (重要)很多的不同输入所得的输出值会均匀的分布在S上(但不是绝对均匀)

最后一个性质对于一个优秀的哈希函数是非常重要的,并且这种均匀与数据的输入规律无关。比如“aa1”、"aa2"经过hash后可能结果会相差很多,当一个哈希函数的输出在S中是均匀的,那么我们将输出值对m取余(%m),就会将不定长输入映射到0~m-1空间中,并且在这个空间也保持均匀分布!哈希表就是这么做的,一会再说!哈希函数还有以下特点:

  1. 免碰撞:即不会出现输入 x≠y ,但是H(x)=H(y) 的情况,其实这个特点在理论上并不成立,比如目前比特币使用的 SHA256 算法,会有

    种输出,如果我们进行
    + 1 次输入,那么必然会产生一次碰撞,事实上,通过 理论证明 ,通过
    次输入就会有99%的可能性发生一次碰撞,不过即使如此,即便是人类制造的所有计算机自宇宙诞生开始一直运算到今天,发生一次碰撞的几率也是极其微小的。
  2. 隐匿性:也就是说,对于一个给定的输出结果 H(x) ,想要逆推出输入 x ,在计算上是不可能的。如果想要得到 H(x) 的可能的原输入,不存在比穷举更好的方法。

常见的哈希函数有:SHA1、MD5、SHA2等

哈希表

哈希表就是利用哈希函数,可以根据关键码而直接进行访问的数据结构,也就是将关键码(Key value)通过哈希函数映射到表中的一个位置来进行访问。由于是直接访问,所以对于哈希表的元素理论上的增删改查时间复杂度都是O(1)。

而计算散列地址的方法有很多种,通常我们使用的是除留余数法,也就是说使用哈希函数对关键字得到的输出值对散列表长度取余得到的余数即为散列地址。

哈希冲突

由于我们的输入长度和范围是任意的,但是经过哈希函数后的输出值域是固定的,所以必然会产生冲突。如上图的buckets152(红色区域)就相当于发生冲突!处理冲突的方法有:

  • 开放地址法
  • 再散列法
  • 公共溢出法
  • 拉链法(经典、重点)
    我们来说下拉链法,也如上图所示,拉链法的思路很简单,就是当发生哈希冲突后,会在当前地址区域建立一个链表,将冲突目标添加到链表中去。这种方式也不太好,当冲突发生过多时,链表的查找方式效率也就不是很高了!
    因此对于JAVA中(C++标准中没有hashmap,只有第三方的),hashmap的实现也是类似,但是有一点改进,也就是如果发生冲突,将冲突对象添加到链表,假设冲突个数达到了8次,那么就会使用红黑树来代替链表,以加快查找速度。冲突个数少时,没有必要使用红黑树

C++中的hash_map

c++的hash_map和map的用法很类似,但一定要区别,map和hash_map虽然都是key-value形式,但是map的底层是红黑树,而hash_map的底层是hash表!如果在Linux下使用hash_map,一定要加上一个__gnu_cxx的命名空间声明!

#include

题目:2G内存下在20亿数据中找到出现次数最多的数

首先我们确定value的范围,如果一个数出现了20亿次,那么value就为20亿次。因此我们使用32位的正整型,也就是4B的空间,同理key也是4B的空间,因此一条记录(Entry)需要8B的空间,当记录为20亿个时,需要至少16GB的内存。
在极端最差的状态,20亿个数都不相同,那么哈希表中可能会有20亿条记录,这样的话显然内存不足,因此一次性统计20个数风险很大。解决方案:将包含有20亿个数的大文件分成16个小文件,利用哈希函数,这样的话,同一个重复的数肯定不会分到不同的文件中去,并且,如果哈希函数足够好,那么这16个文件中不同的数也不会大于2亿(20 / 16)。然后我们在这16个文件中依次统计就可以了,最后进行汇总得到重复数最多的数。当然如果使用分布式系统,那么可以利用哈希函数将这些数据分配到不同的电脑上去!
如果想要看更多精彩内容,请关注我的个人公众号 (算法工程师之路)希望大家多多支持哦~

公众号简介:分享算法工程师必备技能,谈谈那些有深度有意思的算法,主要范围:C++数据结构与算法/深度学习(CV),立志成为Offer收割机!坚持分享算法题目和解题思路(Day By Day)

算法工程师之路

java取余数的函数_左神算法基础:哈希函数和哈希表相关推荐

  1. igs无法分配驱动器映射表_左神算法基础:哈希函数和哈希表

    笔者在读研刚开始的时候,偶尔看面经,有这样一个问题:只用2GB内存在20亿个整数中找到出现次数最多的数,当时的我一脸懵逼,怎么去思考,20亿个数?What The Fuck! 但是,看完今天的文章,你 ...

  2. 左神算法基础班3_13深度拷贝含有随机指针的链表

    Problem: 复制含有随机指针节点的链表 [题目] 一种特殊的链表节点类描述如下: public class Node { public int value; public Node next; ...

  3. 左神算法基础班4_4_3在二叉树中找到一个节点的后继节点

    Problem: 在二叉树中找到一个节点的后继节点 [题目] 现在有一种新的二叉树节点类型如下: public class Node { public int value; public Node l ...

  4. 0206.BFPRT在一大堆数中求其前k大或前k小的问题,简称TOP-K问题(左神算法基础班源码)

    package basic_class_02;/*** * 在一大堆数中求其前k大或前k小的问题,简称TOP-K问题.* 而目前解决TOP-K问题最有效的算法即是BFPRT算法**/ public c ...

  5. 13.在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。(左神算法基础班源码)

    package basic_class_01; /*** *小和问题在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和.求一个数组的小和.例子:[1,3,4,2,5]1左边比1小的数 ...

  6. 左神算法(一)下修改版

    序言: 此篇内容紧跟在左神算法(一)上修改版之后. 左神算法(一)上修改版 左神算法(一)下修改版 左神算法(二) 七.二叉树的基本算法 1.二叉树 2.二叉树的先序.中序.后序遍历 先序:任何子树的 ...

  7. 左神算法中级班第三课[C++代码]

    左神算法中级班第三课[C++代码] 第一题:流水线打包问题[阿里原题] 代码 第二题 代码 第三题:打印螺旋矩阵 代码 第四题 代码 第五题:判读aim是否在矩阵中 代码 第七题:topK问题 代码 ...

  8. java %取余数_计算机取余数java

    Hash Table(哈希表)就是根据对象的特征进行定位的一种数据结构.一个简单的实现方法是将对象通过某种运算得到一个整数,再让这个整数除以哈希表的大小,取其余数,以此作为对象的存储位置. 很多的书上 ...

  9. java取余(java取余数的函数)

    java 求余数 用%就可以. int i = 5; int j = 8; int z = 8 % 5; System.out.println("余数:" + z); 结果为3.上 ...

最新文章

  1. 解决foxmail提示“can not open socket WinSock Error:10106”
  2. Nginx: 413 Request Entity Too Large Error and Solu
  3. 小白学数据分析-----什么是DAU_II [玩家粘性分析模型]为什么游戏粘性会达到60%...
  4. 服务器开机忘记密码怎么修改,服务器忘记mysql密码怎么修改?
  5. 转:概述RAID磁盘的IOPS
  6. 手撸一款精美的水波气泡
  7. 5h是什么意思_2B铅笔中的2B是啥意思?
  8. mongo 修改器 $inc/$set/$unset/$pop/$push/$pull/$addToSet
  9. Arduino Uno ADS1115 数模转换
  10. 一位38岁被裁技术经理的忠告:在职场,这5件事越早做越好
  11. SOT-23封装如何查找元件型号
  12. 进行的vistor实验
  13. 首发国产软硬件完美兼容STM32F407系列功能简介
  14. [数据结构]递归树:借助树求解递归算法的时间复杂度
  15. js百度地图鼠标绘制工具条库
  16. UON:《Detecting Unexpected Obstacles for Self-Driving Cars...》论文阅读与总结
  17. 计算机是怎样跑起来的笔记摘要
  18. 公共WiFi有风险,这些风险你都知道吗
  19. zabbix监控配置QQ邮箱服务
  20. 短视频中的MCN是什么?与PGC UGC有什么不同

热门文章

  1. golang module实践
  2. Python3中异常处理和try/except,try/finally的用法
  3. 有哪些开源的 Python 库让你相见恨晚?
  4. Pycharm使用秘籍
  5. jQuery框架学习第六天:jQuery中的Ajax应用
  6. ASP.NET企业开发框架IsLine FrameWork系列之十三--框架配置信息大全(上)
  7. 如何通过序列化在网络间传递对象,网络协议:轻松定义自己的网络通讯协议
  8. 【opencv有趣应用】基于MobileNet + SSD的物体检测
  9. oracle中表空间详解
  10. extend()与append()的区别