19 | 散列表(中):如何打造一个工业级水平的散列表?

336 阅读2分钟

如何设计散列函数

  • 散列函数的目标\

    • 散列函数不能台复杂
    • 散列函数生成的值要随机并且均匀
  • 散列方法

    • 直接寻址法
    • 平法取中法
    • 折叠法
    • 随机数法
    • ....

装载因子过大怎么办?

  • 装载因子过大

    • 当装载因子达到一定的阈值后,说明hash冲突严重,插入和查询耗时都会增加,需要动态扩容

    • 动态扩容会导致位置发生变化

    • 动态扩容的时间复杂度 均摊后是O(1)

      • 只有最坏是O(n),其余时候为O(1)
  • 装载因子过小

    • 可以考虑动态缩容

如何避免低效扩容

  • 如果装载因子到达阈值,需先扩容,插入数据,插入数据会变得很慢

  • 可以采用渐进式的扩容

    • 先申请新的空间,但是不立即迁移
    • 每次迁移一点
  • 查询时则从新散列表中查找,没有再去老的散列表中查找

\

如何选择冲突解决方法

开放寻址法链表法
优点存储连续空间中,有效利用cpu缓存空间利用率更高
缺点删除数据需要特殊标记冲突代价更高指针需要占据额外的存储空间不能利用CPU缓存
适用场景适用于数据量小,装载因子(<1)小的时候适合存储大对象、大数据量的散列表 比开放寻值法更灵活

工业散列表分析

  • 以HashMap为例

    • 初始化大小=16
    • 装载因子=0.75
    • 利用链表法解决散列冲突
    • 散列函数 hashcode()

总结

  • 工业级的散列表

    • 支持快速地查询、插入、删除操作\

    • 内存占用合理,不能浪费过多的内存空间\

    • 性能稳定,极端情况下,散列表的性能也不会退化到无法接受的情况\

  • 怎么设计

    • 高效的散列函数  随机且均匀

    • 设定装载因子,设计动态扩容策略

    • 选择合适的散列冲突解决方法

      • 开放地址法
      • 链表法