HashMap和HashTable

 

1.  关于HashMap的一些说法:

a)  HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层结构是一个数组,数组中的每一项是一条链表。

b)  HashMap的实例有俩个参数影响其性能: “初始容量” 和 装填因子。

c)  HashMap实现不同步,线程不安全。  HashTable线程安全

d)  HashMap中的key-value都是存储在Entry中的。

e)  HashMap可以存null键和null值,不保证元素的顺序恒久不变,它的底层使用的是数组和链表,通过hashCode()方法和equals方法保证键的唯一性

f)  解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法解决哈希冲突的。

注: 链表法是将相同hash值的对象组成一个链表放在hash值对应的槽位;

   用开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。 沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。

  拉链法解决冲突的做法是: 将所有关键字为同义词的结点链接在同一个单链表中 。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。拉链法适合未规定元素的大小。

HashMap是用来快速查找内容的一种数据结构。使用n个桶存储数据,数据具体存储在哪个桶中是由Hash算法决定的,即对原始内容执行Hash后得出对应桶的序号。

然后这种数据结构会遇到一些问题,由于内存空间有限,所以桶的数量也是有限制的。当桶的数量较小时就容易出现较多内容放在同一个桶中的情况。HashMap中使用默认的0.75作为桶空间的阈值,如果超过这个大小就需要增加桶的数量,以防止较多内容聚集在相同的桶中。

关于为什么0.75就是经常被拿来当做面试问题了。首先通过人脑直观来考虑这个事情,假设我现在有n个桶,那么数据放到多少我需要增加更多的桶呢。这个时候会出现直观的数字0.5,如果桶已经装满一半了那么之后添加内容分配到空桶的概率会低于分配到有内容桶的概率,可想而知从这个点之后将会出现越来越多的内容在相同的桶中。从这里来看这个0.5是个非常优秀的数字它是一个趋势的转折点。

但是这个0.5和负载因子是不一样的,这个0.5我们是指已经有一半的桶被占用了,而HashMap中的负载因子与我们存入的数据总数量相关,并且根据之前对这种数据结构的了解,数据会存在一定概率出现在一个桶中,所以当一半桶都被占用的时候我们实际存储的数据数量是大于0.5n的。

这里假设对于新的内容分配到各个桶的概率是相同的,当前内容数据大小为s。这里使用二项分布的概念,当我们进行了s次插入操作(实验),那么序号0的桶是空桶的概率是多少呢。即:

 

可以明显看出来当s增加P(0)是空桶的概率也会下降,这里用1/2来计算这个分界。即:

 

然后算下负载因子f=(s/n)对n取极限:

 

为了解决这个问题可以先解决这个问题

 

我们得到的结果就是上面式子的倒数即e,把log换成ln即得出我们的负载因子界限值,这个值约等于0.6931,所以0.75的取值范围是与这个界限相近的并且由于基础是16个容量空间,使用0.75也不会算出小数是一个不错的值选取。   

2.  Hashtable和HashMap的区别:

a)   继承不同。

 public class Hashtable extends Dictionary implements Map

public class HashMap extends  AbstractMap implements Map

b)  Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

c)  Hashtable 中, key  value 都不允许出现 null 值。 在 HashMap 中, null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null 。当 get() 方法返回 null 值时,即可以表示 HashMap 中没有该键,也可以表示该键所对应的值为 null 。因此,在HashMap 中不能由 get() 方法来判断 HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断。

d)  两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

e)  哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

f)  Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

 

注:  HashSet子类依靠hashCode()和equal()方法来区分重复元素。

     HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值的,会去判断当前Map中是否含有该Key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值