标签:并且 技术 role height 基于 moc trie 调用 oss
对于随机访问,ArrayList优于LinedList,对于指定位置新增或删除,LinedList优于ArrayList
哈希表本质是一个数组,数组中每一个元素称为一个箱子,箱子中存放的是键值对。
哈希表的存储过程如下:
哈希表的查询过程如下:
哈希表还有一个最重要的属性:负载因子(loadFactor),用于衡量哈希表的空满程度,计算公式为:
负载因子 = 总键值对数/箱子个数
其中,负载因子越大,意味着哈希表越满,越容易导致冲突,性能也就越低,因此,一般当负载因子大于某个常数(通常为0.75)时,哈希表会自动扩容。哈希表自动扩容时,一般会创建两倍于原来个数的箱子,因此即使key的哈希值不变,对箱子个数取余的结果也会发生改变,因此所有键值对的存放位置都有可能发生变化,这个过程称为重哈希(rehash)。
由上可知,尽管哈希表实现了数据的快速查找,但是也带来了两个严重的问题:
(1)如果哈希表中本来的箱子就比较多,扩容时需要重新哈希并移动数据,性能影响较大
(2)如果哈希表设计不合理,哈希表极端情况下会变成线性表,性能较低
因此,如果我们能够预知哈希表中的元素数目,就能通过合理的设置初始容量大小来达到尽量少的扩容的目的以提高哈希表性能。
HashMap的数据结构为数组+链表+红黑树,如下图所示:
哈希冲突的解决主要是通过使用链表和红黑树,具体的选取取决于箱子中存储的键值对数目,若数目少于8个,则只需要关注插删性能,因此采用链表,若数目不少于8个,则对查询效率影响较大,此时适合采用红黑树存储。
首先桶中元素的数目是符合泊松分布的,其中,桶中元素数目概率如下所示:
结合上图,元素数目达到7的概率不到百万分之一。并且对于链表和红黑树的平均查找路径上,当元素数目为6时基本上一致,由于需要考虑链表到红黑树的转化时间,因此一般以7为分水岭,以8作为界限。
LinkedHashMap是HashMap的子类,但是其内部还有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于双向链表中,LinkedHashMap支持插入顺序、访问顺序两种顺序。其中:
【插入排序】:默认顺序为插入顺序,由于hashMap使用node存储,因此天生就是插入顺序,因此LinkedHashMap在使用上未重写put方法,而是重写了get方法,当用户选定根据访问顺序排序时,当前访问的元素会至于末尾。
【访问排序】:重写了get方法,当用户主动的将accessOrder置为true且get或put已存在的数据时会将该数据置于尾部。
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
/**
* 头部节点
*/
transient LinkedHashMap.Entry<K,V> head;
/**
* 尾部节点
*/
transient LinkedHashMap.Entry<K,V> tail;
/**
* 访问顺序指定: <tt>true</tt> 访问顺序排序
* <tt>false</tt> 插入顺序排序
*/
final boolean accessOrder;
Demo:
class DemoClass {
public static void main(String[] args) {
LinkedHashMap map = new LinkedHashMap(10, 0.75f, true);
map.put("hello", "hello");
map.put("hello1", "hello1");
map.put("hello2", "hello2");
map.put("hello2", "hello2");
map.put("hello", "hello");
map.put("hello1", "hello1");
System.out.println(map.values());
}
}
LRU(Least Recently Used,最近最少使用):当超过设定的容量时会淘汰不常使用的数据。
LinkedHashMap可实现LRU缓存的原因有两个:
实现逻辑:
class RLU<K,V> extends LinkedHashMap<K,V>{
/** 设置缓存的最大容量,超过此容量的顶部元素会被淘汰掉**/
private int maxElementNumber;
public RLU(int maxElementNumber){
super(16, 0.75f, true);
this.maxElementNumber = maxElementNumber;
}
/**
* 在LinkedHashMap添加元素后,会调用removeEldestEntry方法,若方法返回true,则头部元素被删除后再将
* 此元素添加到尾部,否则直接添加到尾部。在LinkedHashMap中的实现始终返回false,该子类重写后即可实现对
* 容量的控制。
*/
TreeMap是基于红黑树实现的排序Map,对于增删改查的时间复杂度均为logn,相比于hashMap和LinkedHashMap这些hash表的复杂度O(1),TreeMap的增删改查的时间复杂度为logn就显得有些效率低,但是hashMap并不能保证任何顺序性,LinkedHashMap只能保证了Map的遍历顺序和put顺序一致的有序性。
TreeMap默认排序规则:按照key的字典顺序来排序(升序)。
也可自定义排序规则:要实现Comparator接口。Demo如下:
public static void main(String[] args) {
TreeMap map = new TreeMap(new Comparator<String>() {
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
map.put("hello", "hello");
map.put("hello1", "hello1");
map.put("hello11", "hello2");
System.out.println(map.get("hello1")); // 查找复杂度:logn
}
标签:并且 技术 role height 基于 moc trie 调用 oss
原文地址:https://www.cnblogs.com/huaiheng/p/12820160.html