散列表:如何去优化一个可用的散列表

散列表的查询效率并不能笼统地说成O(1),它给散列表函数,装载因子,散列冲突都有关系

问题 如果散列函数将所有的数据都散列到同一个槽里,如果我们使用的开链方式,那么效率从O(1)退化到O(n)

  如何设计散列函数

  • 均匀化
  • 避免冲突

 装载因子

      装载因子越大,说明散列表中元素越多,空闲位置越少,散列冲突的概率越大,链长,查询慢.

      方法:

      动态扩容:当装载因子过大时,我们可以进行动态扩容,重新申请更大的散列表,将数据搬移到新散列表中,

申请空间为前者的一倍.

     扩容过程

散列表:如何去优化一个可用的散列表

在未孔融时,时间效率为O(1),扩容时,时间复杂度为O(n).

我举一个极端的例子,如果散列表当前大小1GB,要想扩容为原来的两倍大小,那就需要多1GB的数据重hash,并且从原来的散列表转移到新的散列表,一次性 扩容机制 在CPU密集性操作下,会让用户崩溃.

解决方法:当装载因子满载时,我们申请新的空间,但不将老的数据搬移到新的散列表中,

当一个新数据插入时,我们将新数据插入到散列表,,并且从老的散列表拿出一个数据放入到新散列表中.

查找时,我们先从新的散列表中查找,然后在去老的散列表.

 

对比冲突解决的方法

   开放寻址法

      优点:

         散列表存储在数组中,可以有效的利用CPU缓存加快查询速度,

      缺点:

          删除数据的时候比较麻烦,需要标记删除的数据.冲突代价高 ,装载因子的上限不能太大  

    链表法

       优点 :

        内存利用率高,对大装载因子的容忍度更高

        缺点:

       存储至真,对于较小的对象存储是比较消耗内存的      

       改进:  将开链中的链表改造为红黑树结构,提高查询速度 ,优化至O(logn),可以做并发安全,

      

散列表:如何去优化一个可用的散列表