android中map的作用,Android Map相关总结

HashMap、LinkedHashMap、ConcurrentHashMap、ArrayMap、SparseMap、Hashset、TreeMap的底层原理、数据结构与对比

1、HashMap

底层数据结构(数组+链表+红黑树),链表中节点数量大于8则转换为红黑树。

参数对性能的影响:加载因子(loadFactor)和初始容量(initialCapacity)。加载因子跟初始容量得乘积是判断是否需要扩容的依据,当节点个数大于乘积则扩容。如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值(降低后减少碰撞,时间复杂度可以看作O(1));相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1(减小数组的大小,增大碰撞几率)。

hash 函数的意义:

//节点key的hash值计算方法

static final int hash(Object key) {

int h;

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

//根据hash值计算放在哪个桶中

p = tab[i = (n - 1) & hash])

32位hash码右移16位,异或,再与数组长度减1的值做按为与计算,保留后几位的值。右移16位再异或是为了保留高位信息,增大随机性,数组长度减一说明了为什么容量必须是2的倍数。

https://www.zhihu.com/question/20733617

扩容过程:容量变了原来的2倍,同时根据e.hash & oldCap等于0还是1判断是否需要移动。(假设容量16(10000),那么同一个桶中所有节点后4位肯定相同,右数第五位不一定相同),为0则在原来位置,为1则把节点放到原来位置加上扩容容量(原来5,现在是5+16 = 21)。

https://www.cnblogs.com/hongdada/p/6024832.html

线程不安全体现在哪?

1、相同的hash执行插入put()操作可能导致数据被覆盖

2、JDK1.8以前resize()扩容时,是头插入,有可能形成环形链表,导致死循环;JDK1.8以后扩容时是尾插入,不会出现这种情况。

https://blog.csdn.net/v123411739/article/details/78996181

2、LinkedHashMap

底层数据结构:LinkedHashMap继承自HashMap,底层数据结构跟HashMap一样,但是其节点继承HashMap中的Node外,还增加2个指针,before和after,当执行put后,会把after之下新增加的节点,所以LinkedHashMap也可以当作是一个链表。

特点:LinkedHashMap中的链表可以按照插入顺序排序,也可以按照访问顺序排序。当通过get()操作访问某个节点后,会把该节点放到链表的尾部,这也是Lrucache的基础。

使用场景: Lrucache

Lrucache : least recent used,最近最少使用原则。底层使用LinkedHashMap控制缓存在一定的内存容量内。执行put操作时先检查是否超过规定的容量,超过则把最近最少使用的缓存去掉。根据LinkedHashMap按照访问顺序排序的原理,最近访问的元素放在链表尾部,也就是LinkedHashMap最前面的节点替换成新的缓存。

3、ConcurrentHashMap

相对与HashTable在所有方法加锁来确保线程安全,ConcurrentHashMap做了以下优化:通过CAS和锁住桶确保线程安全。CAS避免引起线程切换,消耗cpu资源;而锁住桶相比锁住整个HasMap减小了锁的粒度。(并发put的的时候可能会导致被覆盖,而锁住桶能避免这个问题)

4、ArrayMap、SparseMap

ArrayMap设计上更多考虑的是内存优化,内部使用2个数组进行存储,一个记录key的hash值,另外一个记录key和value,相比hashMap的节点node而言,少了next这个成员变量;而对于数据的插入和获取,采用的二分查找,没有hash算法快,插入时还涉及到数组的搬移,整体的时间效率不如hashMap。

sparseArray的key是int类型,根据key来确定位置,相比HashMap少了key的hash值和next指针;put和add操作同样是基于2分查找。

https://www.jianshu.com/p/7b9a1b386265

http://gityuan.com/2019/01/13/arraymap/

5、HashSet

HashSet 是一个没有重复元素的集合。

它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素。

Set的元素是HashMap的key,value是一个固定的object。通过hash算法实现元素的不可重复以及快速查找。

private transient HashMap map;

private static final Object PRESENT = new Object();

//构造方法

public HashSet() {

map = new HashMap<>();

}

//add

public boolean add(E e) {

return map.put(e, PRESENT)==null;

}

6、TreeMap

主要理解红黑树的2个方面:

红黑树的优势和特性

红黑树什么时候变色,什么时候旋转。

红黑树是一种二叉查找树,由于二叉查找树在插入数据时有可能失衡,变成链表,最坏时间复杂度O(n),通过构造红黑树使得二叉树平衡,最坏时间复杂度为O(logn)。

红黑树有5个特性:

1、每个节点要么是黑色,要么是红色。

2、根节点为黑色。

3、所有叶子节点(nil)为黑色。

4、父子节点不能同时为红色。

5、节点到叶子节点各条路径上黑节点的数量是一样的。

插入节点的时候:

1、默认插入的节点是红色的,避免破坏特性5。

2、插入节点的父节点为黑色时,符合红黑树特性,不做改变。

3、插入节点的父节点为红色时,分为3种情况:

a、父节点为红色,叔叔节点为红色,此时肯定有祖父节点,且祖父节点为黑色,此时需要将父节点和叔叔节点变为红色,祖父节点变为黑色。为什么要这样做?只将父节点变为黑色行不行?不可以,会导致父节点这条路径的黑色节点比叔叔节点路径的黑节点多一,破坏特性5。通过这样子改变能确保符合特性5。

a5fed15efa7f

涂色.png

b、父节点为红色,叔叔节点为黑色,且当前节点为父节点的右节点,此时需要将父节点作为当前节点,进行左旋。

们处理红黑树的核心思想:将红色的节点移到根节点;然后,将根节点设为黑色。既然是“将红色的节点移到根节点”,那就是说要不断的将破坏红黑树特性的红色节点上移(即向根方向移动)。 而S又是一个右孩子,因此,我们可以通过“左旋”来将S上移!

a5fed15efa7f

左旋.png

c、父节点为红色,叔叔节点为黑色,且当前节点为父节点的左节点,此时需要将父节点改为黑色,祖父节点改为红色,同时以祖父节点为当前节点,进行右旋。

a5fed15efa7f

右旋.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值