zoukankan      html  css  js  c++  java
  • 散列表与一致性哈希算法

    一、散列表定义

    散列表用的就是数组支持按照下标随机访问的时候,时间复杂度是 O(1) 的特性,它是一种数组的扩展。我们通过散列函数把元素的键值映射为下标,然后将数据存储在数组中对应下标的位置。当我们按照键值查询元素时,我们用同样的散列函数,将键值转化数组下标,从对应的数组下标的位置取数据。

    工业级的散列表设计应该从以下几个方面考虑:

    (1).设计一个合适的散列函数

    (2).定义装载因子阈值,并且设计动态扩容策略

    (3).选择合适的散列冲突解决方法

    二、散列函数的设计

    散列函数设计的好坏,决定了散列表冲突的概率大小,也直接决定了散列表的性能。

    1.散列函数设计的基本要求

    (1).散列函数计算得到的散列值是一个非负整数;

    (2).如果 key1 = key2,那 hash(key1) == hash(key2);

    (3).如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)。

    其中第三点主要是用来解决散列冲突的问题。

    2.工业级散列函数的设计

    (1).散列函数的设计不能太复杂。过于复杂的散列函数,势必会消耗很多计算时间,也就间接的影响到散列表的性能。

    (2).散列函数生成的值要尽可能随机并且均匀分布,这样才能避免或 者最小化散列冲突,而且即便出现冲突,散列到每个槽里的数据也会比较平均,不会出现某个槽 内数据特别多的情况。

    (3).常见的散列函数设计方法:数据分析法、直接寻址法、平方取中法、折叠法、随机数法等。

    三、散列冲突

    1.常用的散列冲突解决方法

    (1).开放定址法

    定义:开放寻址法的核心思想是,如果出现了散列冲突,我们就重新探测一个空闲位置,将其插入。在开放定址法中,常用的探测插入位置方法有线性探查法、二次探查法、双重散列法等

    性能描述:当散列表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了 尽可能保证散列表的操作效率,一般情况下,会尽可能保证散列表中有一定比例的空闲槽位。用装载因子(load factor)来表示空位的多少。计算公式:

    散列表的装载因子 = 填入表中的元素个数 / 散列表的长度

    适用场景:当数据量比较小、装载因子小的时候,适合采用开放寻址法。这也是 Java 中的ThreadLocalMap使用开放寻址法解决散列冲突的原因。

    (2).链表法

    定义:当插入的时候,我们只需要通过散列函数计算出对应的散列槽位,将其插入到对应链表中即可, 所以插入的时间复杂度是 O(1)。

    适用场景:基于链表的散列冲突处理方法比较适合存储大对象、大数据量的散列表,而 且,比起开放寻址法,它更加灵活,支持更多的优化策略,比如用红黑树或者跳表来代替链表。可以使得访问效率更高。

    注意:

    1.在插入或查找的时候,计算Key被映射到桶的位置:

    int index = hash(key) & (capacity - 1)
    hash()扰动函数计算的值和hash表当前的容量减一,做按位与运算。
    这一步,为什么要减一,又为什么要按位与运算?
    因为A % B = A & (B - 1),当B是2的指数时,等式成立。
    本质上是使用了「除留余数法」,保证了index的位置分布均匀。

    2.为什么HashMap的数组长度必须是2的整次幂?
    数组长度是2的整次幂时,(数组长度-1)正好相当于一个**“低位掩码”**,“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。

    以初始长度16为例,16-1=15。2进制表示是00000000 00000000 00001111。“与”操作的结果就是截取了最低的四位值。也就相当于取模操作。

    3.一致性哈希算法

    http://www.zsythink.net/archives/1182

    参考:1、极客时间《数据结构与算法之美》

       2、http://www.zsythink.net/archives/1182

  • 相关阅读:
    02_java基础学习_基础语法(上)01_day02总结
    EditPlus如何设置保存时不产生.bak备份文件?
    UltraEdit(UE)如何设置去掉.bak备份文件?
    如何在win10上连接苹果无线键盘
    01_java基础学习_Java概述_day01总结
    Python 提取Twitter tweets中的元素(包括text, screen names, hashtags)
    #leetcode#Path Sum II
    怎样实现广度优先遍历(BFS)
    GCD编程-串行队列与并发队列
    在对方电脑建立IPC连接, 利用IPC$入侵 运行木马
  • 原文地址:https://www.cnblogs.com/jianglinliu/p/11188855.html
Copyright © 2011-2022 走看看