zoukankan      html  css  js  c++  java
  • [算法]散列表( Hash Table)

    国庆假期在看<算法图解>这本书,感觉很有意思.
    结合学到的知识,以及我的理解,来聊聊散列表这部分的内容.

    假设你现在在一家超市工作,有顾客来买东西时,需要在一个本子上查找价格.如果记录价格的本子不是按照字母顺序来排列的,为了找一个商品的价格,可能 1 分钟的时间就过去了.如果让顾客等这么长时间,确定这家超市还能存活下去?
    为了提高准确找到商品的价格,咱们可以对这个方法进行一个优化.第一想到的应该就是让本子的记录内容由顺序,比如从 A 到 Z 来开始排列,这样如果顾客拿着「可乐」来结账的时候,只需要定位到 k 开头的位置就行了,然后再寻找.
    这样的方式是比刚开始好很多,但是你要知道,顾客就是上帝啊!顾客才不会等这么长时间.顾客期望的结果是什么,你看到这个商品,立刻就能知道是多少钱,结完账立刻让顾客走.
    这个时候怎么办?是不是觉得如果有个机器人,能够装得下所有商品的价格就好了?这样顾客来了,问一下机器人就可以知道了.

    在计算机中,有一种数据结构就可以满足这个场景,叫散列表,说它的另外一个名字可能就不生疏了,哈希表( Hash Table ),它由健和值组成,最大的特点就是,不管你要访问什么,它的反应时间都是 O(1).
    数组和链表都是直接被映射到内存,但是散列表不一样,它使用散列函数来确定元素的存储位置.

    散列函数如果想要符合上面的应用场景,必须满足一些要求:

    • 数据必须是一致的.比如,我第一次输入苹果的时候,得到的价格是 4 元/斤,那我下次输入苹果的时候,也必须是 4 元/斤才行.
    • 对于不同的输入,应该有不同的输出.如果不管我输入什么值,你都返回给我同样的值,这就不能认为是一个好的散列函数.
    • 散列函数知道数组有多大,只返回有效的索引,假设数组包含 5 个元素,结果散列函数返回无效索引 100 ,就不能满足上面的应用场景.

    基于散列函数和数组,在以下应用场景中可以考虑使用散列表:
    1 ,用于查找.
    前一段时间一直分享网络方面的知识,估计看到这里也会比较熟悉, DNS 解析的时候,就是将一个网站映射到了 IP 地址,这样用户才能访问到一些资源.而散列表就是提供这种功能的方式之一.
    2 ,防止重复.
    现在需要大家来投票进行选择新人奖,很显然,不能刷票吧,一个人只能投一票.但是如何避免重复投票呢?是不是有人来投票的时候,将他的名字和已经投过票的名单进行对比就行了,如果有,那就不让投了,如果没有,可以投票.
    这个时候,创建一个散列表,用来记录已经投过票的人,接下来有人投票时,检查是否在散列表中,如果在,抱歉不能投了,如果不在,可以投票.
    3 ,可以用做缓存.
    缓存这个应该是比较熟的,网站为了提高用户的体验度,都会做缓存.那么这些缓存是如何存储的呢?
    没错,缓存的数据存储在了散列表中!
    因为它的运行时间为 O(1) ,用户来访问的时候,可以通过这种方式,快速给用户以反馈.

    但是散列函数也是有自己的不足的.
    在上面,我们忽略了一点,就是空间是有限的.
    如果只有 5 个空间,但是通过散列函数输入了 6 个值,肯定会有一个冲突,怎么办?
    方法有很多,比如线性探测法,二次探测法,随机弹测法等等,最简单的就是如果两个键映射到了同一个位置,那就在这个位置再存储一个链表.
    如果数据量很大,就有一种可能,这个位置的链表会很长很长,这个时候,散列表的速度就会很慢.

    这个时候,就能看到一个好的散列函数的重要性了.
    如果有一个好的散列函数,那就不会出现上面的问题.
    什么是好的散列函数呢?一般是拿填装因子来确定的.填装因子很好计算,就是散列表中有多少,总数有多少,两者一除就是填装因子.假设建有一个散列表,有 3 个位置,用了 1 个,那么这个散列表的填装因子就是 1/3 .

    目前,大多数语言都提供散列表的实现,所以单单从使用上来说,不需要 care 如何实现.
    以上,感谢您的阅读~

  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/zll-0405/p/12534110.html
Copyright © 2011-2022 走看看