本文部分内容摘自网络,参考资料链接会在文后给出,在此感谢原作者的分享。

计算理论中,没有Hash函数的说法,只有单向函数的说法。所谓的单向函数,是一个复杂的定义,大家可以去看计算理论或者密码学方面的数据。用“人类”的语言描述,单向函数就是:如果某个函数在给定输入的时候,很容易计算出其结果来;而当给定结果的时候,很难计算出输入来,这就是单向函数。各种加密函数都可以被认为是单向函数的逼近。Hash函数(或者称为散列函数)也可以看成是单向函数的一个逼近。即它接近于满足单向函数的定义。

Hash函数还有另外的含义。实际中的Hash函数是指把一个大范围映射到一个小范围。把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存。除此以外,Hash函数往往应用于查找上。所以,在考虑使用Hash函数之前,需要明白它的几个限制:

  • Hash的主要原理就是把大范围映射到小范围;所以,你输入的实际值的个数必须和小范围相当或者比它更小。不然冲突就会很多。
  • 由于Hash逼近单向函数;所以,你可以用它来对数据进行加密。
  • 不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单项函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。

由于实现了Hash的数据结构支持随机读取(即直接定位,而不需要涉及各类查找算法),检索效率非常高,成为了很多存储引擎的首选,著名的有redis、memcache等,但是Hash的特性决定了一些应用场景下的不足:

  • Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
  • Hash 索引无法被用来避免数据的排序操作。(即Hash函数并不会自排序,相对的如B树,本身带有排序信息,在节点增删改时按规则维护)
  • Hash 索引不能利用部分索引键查询。

稍加扩展的话,我们还可以将Hash应用在各种数据分布式技术中,这方面说的比较多的是“一致性哈希算法”,著名的开源分布式NoSQL数据库系统Cassandra就应用了这一算法。

对于数据检索的低层面应用,主要是各类集合类型。在设计相关类型时,要考虑适当的Hash算法,考虑因素主要是以下几个方面:

  • 计算Hash值所需的时间。
  • Hash表长度。
  • Hash值分布情况。
  • 数据的查找频率。
  • Hash值冲突(重复)的概率。

冲突解决技术可分为两大类:开散列法(又称为链地址法)和闭散列法(又称为开发地址法)。可假设实现Hash结构时,数据存放在预先用数组实现的一片连续的地址空间,两种冲突解决技术的区别在于发生冲突的元素是存储在这片数组的空间之外(开散列法,一般为附加链表形式)还是空间之内(闭散列法)。与闭散列法相比,开散列法有如下优缺点:

  • 开散列法处理冲突无二次聚集现象,因此平均查找时间较短。
  • 由于开散列法中各链表上的节点空间是动态申请的,因此适合无法确定表长的情况。
  • 指针需要额外空间,故当记录规模较小时,闭散列法较为节省空间。
  • 在.NET中,链表的各个元素分散于托管堆各处,这会给垃圾回收带来压力,影响程序性能。

在C#中,实现了Hash函数的集合类我知道的有两个:System.Collections.Hashtable和System.Collections.Generic.Dictionary<TKey,TValue>,这两者区别如下:

  • Hashtable采用闭散列法来解决冲突,而Dictionary采用开散列法来解决冲突。
  • Hashtable在空间不够时,会自动扩容,在扩容时会重新计算所有元素的哈希码和哈希地址,会消耗大量时间进行计算,Dictionary不存在这个问题(自然Dictionary在空间不够时也要开辟新的空间,不过不需要重新计算和安排原有数据的哈希值和哈希地址,这方面内容可看Dictionary的源码便一清二楚了。
  • Hashtable的线程安全包含几个层次,默认可由多个读取器线程一个写入线程使用;若要允许多线程写入(在没有线程读取的情况下),则需要通过Synchronized方法返回的包装完成;如果使用一个或多个读取器以及一个或多个编写器,则Synchronized包装不提供线程安全的访问,此时应使用SyncRoot锁定集合。(MSDN说了这么多,然后告诉我说Hashtable是线程安全的,难道不是在玩我?)Dictionary没这么复杂,只要Lock(SyncRoot)即可。

ps:关于NoSql,文中涉及了若干NoSql数据库,博主就在此简单说下对NoSql的一些个人见解。现在NoSql可谓风生水起,恰如当年web2.0、ajax刚兴起的时候,其实都不是非常高深的技术,但却能打破传统,一领风骚好多年,所以说技术是其次,思想才是最重要的。ok扯远了,NoSql和Sql存储引擎差不多,总归就那么几种,文中说到的Hash是一种,B数是一种,还有LSM树之类的,顶多在局部稍作改进以适应场景。它们真正的区别在于,NoSql不必非常顾忌数据库范式的约束,从而极大提高了读写速度和扩展能力,比如写操作不care事务,在每秒写几万几十万的数据量下,光这点就能甩Sql几条街。可以说各类NoSql的争奇斗艳,其实都是以取消或部分取消数据库范式的约束为前提,看似很小的改变,能换来性能的巨大提升,当然这也伴随着数据冗余、安全性不高等Sqls深恶痛绝的问题。上帝总是公平的,任何事物都没有绝对的好坏,就看你把它们用在什么地方。

参考资料:

Hash函数的几种

一致性哈希算法应用及优化(最简洁明了的教程)

三种基本的存储引擎比较

NoSQL数据库探讨之一 - 为什么要用非关系数据库?

转载请注明本文出处:http://www.cnblogs.com/newton/p/4561273.html

Hash函数及其应用的更多相关文章

  1. Hash 函数及其重要性

    不时会爆出网站的服务器和数据库被盗取,考虑到这点,就要确保用户一些敏感数据(例如密码)的安全性.今天,我们要学的是 hash 背后的基础知识,以及如何用它来保护你的 web 应用的密码. 申明 密码学 ...

  2. Bitset<>用于unordered container时的默认hash函数

    自从c++11起,bitset用于unordered container,将会提供默认的hash函数. 在gcc中,相关代码如下: // DR 1182. /// std::hash speciali ...

  3. 各种字符串Hash函数比较(转)

    常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法.这些函数使用位运算使得每一个字符都对最后的函数值产生影响.另外还有以MD5和SHA1为代表的杂凑函数,这些函数几乎 ...

  4. hash函数为什么要选择对素数求余?

    常用的hash函数是选一个数m取模(余数),这个数在课本中推荐m是素数,但是经常见到选择m=2^n,因为对2^n求余数更快,并认为在key分布均匀的情况下,key%m也是在[0,m-1]区间均匀分布的 ...

  5. 理解php Hash函数,增强密码安全

    1.声明 密码学是一个复杂的话题,我也不是这方面的专家.许多高校和研究机构在这方面都有长期的研究.在这篇文章里,我希望尽量使用简单易懂的方式向你展示一种安全存储Web程序密码的方法. 2.“Hash” ...

  6. 长度有限制的字符串hash函数

    长度有限制的字符串hash函数 DJBHash是一种非常流行的算法,俗称"Times33"算法.Times33的算法很简单,就是不断的乘33,原型如下 hash(i) = hash ...

  7. [转]各种字符串Hash函数比较

    转自:https://www.byvoid.com/zht/blog/string-hash-compare 常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法.这些 ...

  8. 学习hash_map从而了解如何写stl里面的hash函数和equal或者compare函数

    ---恢复内容开始--- 看到同事用unordered_map了所以找个帖子学习学习 http://blog.sina.com.cn/s/blog_4c98b9600100audq.html (一)为 ...

  9. Hash函数的安全性

    我们为了保证消息的完整性,引进了散列函数,那么散列函数会对安全正造成什么影响呢?这是需要好好研究一番的问题. 三个概念: 1.如果y<>x,且h(x)=h(y),则称为碰撞. 2.对于给定 ...

随机推荐

  1. 前端学习 第三弹: JavaScript语言的特性与发展

    前端学习 第三弹: JavaScript语言的特性与发展 javascript的缺点 1.没有命名空间,没有多文件的规范,同名函数相互覆盖 导致js的模块化很差 2.标准库很小 3.null和unde ...

  2. jsp xml servlet

    什么都懂一点,什么都不精通!!

  3. React组件性能优化

    转自:https://segmentfault.com/a/1190000006100489 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层:它使用虚拟DOM ...

  4. MAC的终端命令

    今天小研究了一下MAC的终端命令,主要为了方便调试程序用,XCODE用不来啊... 在这里记下..防止丢失 pwd 当前工作目录 cd(不加参数) 进root cd(folder) 进入文件夹 cd ...

  5. 【组合数学】 02 - Möbius反演公式

    计数问题种类繁多,为了避免陷入漫无目的烧脑运动,我们先需要关注一些常用方法和结论.数学的抽象性和通用性是我们一直推崇的,从诸多特殊问题中发现一般性的方法,也总会让人兴奋和慨叹.一般教材多是以排列组合开 ...

  6. Json格式应用

    Json格式在用于数据存储方面比xml有着空间上的优势,Json格式又主要分为两种格式:名称/值 对 和数组. 在我的业务环境中需要先把一种空间比较小的格式. 测试如下: 取数据库中的一张表然后生成两 ...

  7. OAF_开发系列03_实现OAF如何在保存前判断数据是否存在变更(案例)

    2014-06-26 Created By BaoXinjian

  8. 一个非常牛比的前端google插件

    WEB前端助手(FeHelper) 用了都说好,嘻嘻

  9. centos 安装rmagick 2.13.4出错

    因为安装redmine,缺少rmagick,使用bundle install安装依赖的gem,报错如下: 然后,网上查询一下,都是ubuntu系统下的解决方案. centos下正确的解决方法如下: y ...

  10. php三维数组去重

    假设叫数组 $my_array; // 新建一个空的数组. $tmp_array = array(); $new_array = array(); // 1. 循环出所有的行. ( $val 就是某个 ...