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 如何实现.
    以上,感谢您的阅读~

  • 相关阅读:
    回答提出的问题1-17章
    《构建之法》第13-17章读书笔记
    读《一个程序员的生命周期》有感
    构建之法的第十、十一、十二章读书笔记
    阅读《构建之法》第8,9,10章
    5.2-5.3
    作业5.1测试与封装
    读《构建之法》5.6.7 思考
    读《构建之法》的思考
    作业2 结对思则运算
  • 原文地址:https://www.cnblogs.com/zll-0405/p/12534110.html
Copyright © 2011-2022 走看看