zoukankan      html  css  js  c++  java
  • 哈希表底层深入


    图片

    图片



    1.哈希表的底层结构?
    Java中的HashSet和HsahMap用的就是哈希表

    数据结构决定了数据的检索,维护的效率。数组的检索效率高,增删元素的效率低。而链表的增删元素的效率高,检索元素的效率低。而哈希表结合了他们的优点。检索与增删效率都高。哈希表的底层结构就是一个数组,数组的长度即哈希表的长度,数组中的每个空间(也叫桶)存放的是一条链表,链表中的每个节点用来存放元素。即一个数组的每个数组元素是一条链表,链表的每个节点存放元素,可以将数组的每个元素看做桶,桶里面可以有多个元素。桶里元素直接的数据结构是链表。


    2.哈希表如何检索元素?

    哈希表首先根据要存放的元素的key得到hash值,将这个hash值经过"特殊计算的"结果,作为数组的下标(定位桶),进而确定将要遍历的链表。就不用遍历所有的链表,所以检索效率高。


    3.哈希表如何增删元素?

    首先一个哈希表的默认初始长度为16,即数组有16个空间(并非指能放16个元素)。默认加载因子为0.75。当向哈希表中添加元素的时候先判断是否要扩容,如果当前元素的总个数大于16*0.75那么要进行扩容,新的容量为原来的2倍。

    在向哈希表中添加元素时首先通过要添加的元素的key的hash值,经过特殊算法计算的值作为下标,确定这个元素要放到数组中的那个桶里,然后遍历这个桶里的链表中的每个元素,与key进行equals判断如果equals返回false说明这个元素在哈希表中不存在则插入。如果返回true则不插入。

    4.如何计算下标值?

    通过要插入的元素的key调用hashcode方法得到哈希值,并与哈希表的长度减一进行与运算得到数组下标。
    公式:hash(key)&table.length-1
    由于哈希表表长一定是2的指数,即table.length-1的结果的二进制一定全部是1(比如16-1)与hash(key)进行与运算,即hash(key)最高位全为0,即求hash(key)与表长的余数,得到的就是下面的公式。
    hash(key)%(table.length)。

    这就可以解释当表长为16,元素个数不超过16*0.75时,插入元素就会根据要插入元素的key的的hashcode值与表长取余得到下标,这样在不超过表长的前提下,元素就会散乱的分布在这16不同的桶里。而决定链表的长度主要由加载因子决定。即使hashcode值不同但与表长进行取余,得到的下标会相同,这样就会散乱的分布在16个桶里

    hash()

    static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }

    hash值找到对应索引

    static int indexFor(int h, int length) { return h & (length-1); }

    HashMap中则通过h&(length-1)的方法来代替取模,同样实现了均匀的散列,但效率要高很多,这也是HashMap对Hashtable的一个改进。

    length为2的整数次幂的话,h&(length-1)就相当于对length取模,这样便保证了散列的均匀,同时也提升了效率。

    说明:length为2的整数次幂的话,为偶数,这样length-1为奇数,奇数的最后一位是1,这样便保证了h&(length-1)的最后一位可能为0,也可能为1(这取决于h的值),即与后的结果可能为偶数,也可能为奇数,这样便可以保证散列的均匀性,而如果length为奇数的话,很明显length-1为偶数,它的最后一位是0,这样h&(length-1)的最后一位肯定为0,即只能为偶数,这样任何hash值都只会被散列到数组的偶数下标位置上,这便浪费了近一半的空间。



    5.哈希表中的单链表的稀疏程度决定因素?

    单链表的稀疏程度决定检索效率高低,而加载因子可以决定元素的个数,进而决定单链表的稀疏程度,哈希初始初始容量越大,加载因子越小,而实际存放的元素越少,单链表越稀疏越接近于数组。检索效率越高,但是越接近于数组,增钱效率就降低了,所以加载因子的大小一定要根据实际需求。

    6.hashcode怎么写?
    由哈希表在插入元素的时候会调用对象的hashcode方法和equals方法,因此重写十分必要。
    原则:
    两个对象的equals返回true,那么他们的hashcode一定要相等。

    两个对象的hashcode相同,他们的equals不一定返回true。
     
  • 相关阅读:
    你不知道的多重循环的事情
    【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
    ssh 远程登陆指定port
    GMT和CST的转换
    Swift新手教程系列5-函数+selector在swift中的使用方法
    Mac OS X 10.10, Eclipse+ADT真机调试代码时,Device Chooser中不显示真机的解决方式
    android studio 0.8.1使用和遇到问题解决
    C语言之函数调用17—递归法之中的一个般函数的调用(2)
    C语言之基本算法25—牛顿迭代法求方程近似根
    FineUI之使用SQL脚本从数据库表中生成对应的输入控件
  • 原文地址:https://www.cnblogs.com/chaeyeon/p/7068407.html
Copyright © 2011-2022 走看看