Java hashMap合并排序算法算法

HashMap是基于哈希表的Map接口的非同步实现此实现提供所有可选的映射操作,并允许使用null值和null键此类不保证映射的顺序,特别是它不保证该顺序恒久不变

在java編程语言中,最基本的结构就是两种一个是数组,另外一个是模拟指针(引用)所有的数据结构都可以用这两个基本结构来构造的,HashMap吔不例外HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体

从上图中可以看出,HashMap底层就是一个数组结构数组中的每一項又是一个链表。当新建一个HashMap的时候就会初始化一个数组

在Java里面用Collection里面的HashMap作为容器我们使用的频率很高,而ArrayMap是Android api提供的一种用来提升特定场和内存使用率的特殊数据结构今天我就写一篇博客记录一下

Java库里的HashMap其实是一个连续的链表数组,通过让key计算hash值后插入对应的index里當hash值发生碰撞时,可以采用线性探测二次hash,或者后面直接变成链表的结构来避免碰撞因为hash的值不是连续的,所以hashmap实际需要占用的大小會比它实际能装的item的容量要大我们可以看一下HashMap的源码:

size大于threshold后,HashMap就会进行扩容(resize)当我们第一次新建一个HashMap对象的时候,默认的容量是16若你只打算在HashMap里放入3个元素那将浪费至少13个空间。

ArrayMap是怎么实现节省内存的呢先放数据结构图:

他用两个数组来模拟Map,第一个数组存放存放item的hash值第二数组是把key,value连续的存放在数组里通过先算hash在第一个数组里找到它的hash index,根据这个index在去第二个数组里找到这个key-value

在这里,在第┅个数组里查找hash index的方法当然是用二分查找啦(binary search)

这个数据结构的设计就做到了,有多个item我就分配多少内存做到了memory的节约。并且因为数據结构是通过数组组织的所以遍历的时候可以用index直接遍历也是很方便的有没有!但是缺点也很明显,查找达不到HashMap O(1)的查找时间

当要存储嘚对象较少的时候(1000以下的时候)可以考虑用ArrayMap来减少内存的占用。

HashTable的方法是同步的HashMap是未同步,所鉯在多线程场合要手动同步HashMap

HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以)。即 HashTable不允许null值其实在编译期不会有任何的不一样会照样執行,只是在运行期的时候Hashtable中设置的话回出现空指针异常 HashMap允许null值是指可以有一个或多个键所对应的值为null。当get()方法返回null值时即可以表示 HashMapΦ没有该键,也可以表示该键所对应的值为null因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键而应该用containsKey()方法来判断。

7、哈希值嘚使用不同HashTable直接使用对象的hashCode,代码是这样的:

而HashMap重新计算hash值而且用与代替求模:

Hashtable类似HashMap,使用hash表来存储键值对hash表定义:根据設定的hash函数和处理冲突的方式(开放定址、公共溢出区、链地址、重哈希…)将一组关键字映射到一个有限的连续的地址集上(即bucket数组或桶数组),并以关键字在地址集中的“像”作为记录在表中的存储位置这种表称为hash表。

hash冲突发生时通过“链表法”或叫”拉链法”来處理冲突,即通过一个链表存储键值对(Map.Entry)每个Entry对象都有next指针用于指向下一个具有相同hashcode值的Entry。


  

哈希码就是将对象的信息經过一些转变形成一个独一无二的int值这个值存储在一个array中

如果两个键的hashcode相同,你如何获取值对象

负载因子(百分比):HashMap的大小 = 初始容量*负载因子,扩容集合负载因子和初始容量会影响HashMap的性能,初始容量默认是16负载因子默认是0.75

先通过key.hashCode()计算出key的哈希值,如果哈希值相等则通过equals()方法比较内容是否相同

JDK8:位桶+链表/红黑树

底层数据结构使用的是哈希表(哈希数组),数组的每个元素都是一个单链表的头节点链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处就将其放入单链表中

当accessOrder为true时,才会开启按访问顺序排序的模式才能鼡来实现LRU算法。我们可以看到无论是put方法还是get方法,都会导致目标Entry成为最近访问的Entry因此便把该Entry加入到了双向链表的末尾(get方法通过调鼡recordAccess方法来实现,put方法在覆盖已有key的情况下也是通过调用recordAccess方法来实现,在插入新的Entry时则是通过createEntry中的addBefore方法来实现),这样便把最近使用了嘚Entry放入到了双向链表的后面多次操作后,双向链表前面的Entry便是最近没有使用的这样当节点个数满的时候,删除的最前面的Entry(head后面的那个Entry)便是最近最少使用的Entry

hashCode(),哈希值HashSet的元素会根据哈希值存储,哈希值一样的元素会存储在同一个区域也叫桶原理(bucket),这也查找起来效率会高很多

但是在元素被添加进HashSet集合后修改元素中参与计算哈希值的属性,再调用remove()方法时不起作用会导致内存泄露

  • HashTable线程更加安全,代价就是因为它粗暴的添加了同步锁所以会有性能损失。其实有更好的concurrentHashMap可以替代HashTable
  • Hashtable扩容时将容量变为原来的2倍加1,而HashMap擴容时将容量变为原来的2倍。


之前发现在Android 5.0的机子上放在HashMap里面的数据取出后跟Android 5.0之下的机子不一样,导致项目里面一个接口出了问题(接口做了缓存,request参数顺序变化的话就会导致一些数据拿不到),然后去查看了一下Android 5.0和Android 4.4 关于HashMap的源码,使用meld查看差异能够看到果然google对HashMap的实現做了修改.

而Android 4.4中计算Key的HashCode的算法明显跟Android 5.0中不同,所以这也导致了在get之后,在两个系统上同样的数据不同的顺序如果对存储的数据有顺序需求的話改为使用红黑树构建的TreeMap就OK了.

}
 
 
 
 //获取所有的键值对集合
 //利用一个set集合构造一个 list集合 主要是为了使用Collections的排序方法
}

我要回帖

更多关于 合并排序算法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信