
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。