【算法】散列表(hash table)

为何散列表会出现

  • 场景:若是超市买东西结帐的时候,售货员在一个本子里查找价格
  • 若是是有序的(二分查找)还好,时间是 O(logn),若是是无序(简单查找)的话,那就是 O(n)
  • 若是直接有一个 O(1)的查找速度就行了

散列函数

将输入映射到数字数组

  • 一致性:输入 apple 时获得的是 4,那么每次输入 apple 都必须是 4
  • 不一样性:不一样的输入将获得不一样的输出。若是输入 apple 和 yoki 都获得 4,那么这是一个很差的散列函数。

创造散列表

结合散列函数和数组浏览器

  • 建立一个空数组
  • apple 输入到散列函数,输出 3,而后把 apple 的价格存储到数组索引 3
  • 接着各个类推,知道存完数组
  • 而后咱们要找 apple 的价格,就把 apple 输入交给散列函数,获得 3 去数组里面找

散列表的经典应用

查找,防止重复,用于缓存缓存

查找

  • 被用于大海捞针的查找
  • 这个就不用细说了,相似的有 dns 解析

防止重复

场景:负责一个投票站,每一个人只能投一票,如何避免重复投票服务器

  • 有一个方法是:有人来投票,就将它记录在一个投票名单里面,而后接下来的人都遍历这个投票名单,若是有就不能投票,可是这样就列表会愈来愈长,就会变慢
  • 另一种就是散列表,超快

缓存

  • 浏览器缓存的数据存储在散列表里面
  • 若是访问 facebook 的页面,会先检查散列表中是否存储了该页面
  • 若是不在缓存中,才去访问服务器,而后把数据放到缓存里,这样下次有人访问就能够直接命中缓存

冲突

事实上不可能不一样的输入都能得到不一样的值app

  • 假设有一个数组包含 26 个位置,而咱们使用的散列函数很是简单,按照字母表顺序分配位置
  • apple 第一个,bear 第二个,接下来来了一个 banana,理应分到第二个,可是这个时候第二个位置已是 bear 了
  • 这个就叫冲突,解决冲突的办法有不少,简单的就是在这个冲突的位置存储一个链表,bear 末尾的指针指向 banana
  • 因此散列函数很重要,好的散列函数将 key 均匀的映射到散列表的不一样位置

如何避免冲突

  • 较低的填装因子
    • 散列表包含的元素数:位置总数就是填装因子
    • 越小越好,满了只能调整长度,换一个更长的数组
    • 一个不错的经验规则就是,一旦填装因子大于 0.7,那么就要调整散列表的长度
  • 良好的散列函数
    • SHA 函数

散列表性能如何

平均状况

  • 查找,插入,删除都是 O(1),常量时间

最糟糕状况

  • 查找,插入,删除都是 O(n),线性时间

为何会有两种状况,这是由于有了冲突可能会靠链表解决,n 个长度的链表,最好状况下没有冲突,就常量时间 )函数

相关文章
相关标签/搜索