Java数据结构篇

Map体系

1.HashMap

  • 哈希冲突:开放定址法、再哈希法、链地址法
  • 插入元素先检查是否到达阈值,是则先数组扩容,然后再插入链表,链表长度超过8则转红黑树
  • 1.7之前由于扩容导致的头插法尾插法混合导致指针错误,出现死循环问题

2.TreeMap

基于红黑树,增加了排序功能,默认使用Java自带排序规则,没有则需要实现Comparable接口(大于等于小于分别返回1,0,-1)

🌟下面是并发安全容器,HashTable和ConcurrentHashMap基于HashMap,而ConcurrentSkipListMap基于TreeMap

3.HashTable

   在数据不断地写入和删除,且不存在数据量累积以及数据排序的场景下,我们可以选用Hashtable或ConcurrentHashMap。Hashtable使用Synchronized同步锁修饰了put、get、remove等方法,因此在高并发场景下,读写操作都会存在大量锁竞争,给系统带来性能开销。

4.ConcurrentHashMap

   相比Hashtable,ConcurrentHashMap在保证线程安全的基础上兼具了更好的并发性能。在JDK1.7中,ConcurrentHashMap就使用了分段锁Segment减小了锁粒度,最终优化了锁的并发操作。到了JDK1.8,ConcurrentHashMap做了大量的改动,摒弃了Segment的概念。由于Synchronized锁在Java6之后的性能已经得到了很大的提升,所以在JDK1.8中,Java重新启用了Synchronized同步锁,通过Synchronized实现HashEntry作为锁粒度。这种改动将数据结构变得更加简单了,操作也更加清晰流畅。

   与JDK1.7的put方法一样,JDK1.8在添加元素时,在没有哈希冲突的情况下,会使用CAS进行添加元素操作;如果有冲突,则通过Synchronized将链表锁定,再执行接下来的操作。因此按理说在性能上ConcurrentHashMap要好一些,通常为首选。但要注意一点,虽然ConcurrentHashMap的整体性能要优于Hashtable,但在某些场景中,ConcurrentHashMap依然不能代替Hashtable。例如,在强一致的场景中ConcurrentHashMap就不适用,原因是ConcurrentHashMap中的get、size等方法没有用到锁,ConcurrentHashMap是弱一致性的,因此有可能会导致某次读无法马上获取到写入的数据。

5.ConcurrentSkipListMap

   ConcurrentHashMap容器,该容器在数据量比较大的时候,链表会转换为红黑树。红黑树在并发情况下,删除和插入过程中有个平衡的过程,会牵涉到大量节点,因此竞争锁资源的代价相对比较高。而跳跃表的操作针对局部,需要锁住的节点少,在并发场景下的性能会更好一些,因此就实现了在非线程安全的Map容器中,用TreeMap容器来存取大数据;在线程安全的Map容器中,用SkipListMap容器来存取大数据。
在这里插入图片描述
在这里插入图片描述

List体系

1.LinkedList

  • 双向链表
  • 内部属性
    在这里插入图片描述

2.ArrayList

  • 实现接口List,Clonable,Serializable,RandomAccess(空接口,仅用于标识)
  • 从ArrayList属性来看,它没有被任何的多线程关键字修饰,但elementData被关键字transient修饰了。这就是我在上面提到的第一道测试题:transient关键字修饰该字段则表示该属性不会被序列化,但ArrayList其实是实现了序列化接口,这到底是怎么回事呢?

在这里插入图片描述  这还得从“ArrayList是基于数组实现“开始说起,由于ArrayList的数组是基于动态扩增的,所以并不是所有被分配的内存空间都存储了数据。  如果采用外部序列化法实现数组的序列化,会序列化整个数组。ArrayList为了避免这些没有存储数据的内存空间被序列化,内部提供了两个私有方法writeObject以及readObject来自我完成序列化与反序列化,从而在序列化与反序列化数组时节省了空间和时间。

  因此使用transient修饰数组,是防止对象数组被其他外部方法序列化。

  • 扩容策略,1.5倍+1,可以自行预估存储量指定初始容量,减少扩容次数,提高性能;
  • 插入和删除中间节点需要重排列位置,直接末尾操作则不需要;
  • 遍历过程中可以增加删除元素吗?可以使用iterator迭代器进行安全操作,hashmap同理;

3.vector

  Vector也是基于Synchronized同步锁实现的线程安全,Synchronized关键字几乎修饰了所有对外暴露的方法,所以在读远大于写的操作场景中,Vector将会发生大量锁竞争,从而给系统带来性能开销。

4.CopyOnWriteArrayList

相比之下,CopyOnWriteArrayList是java.util.concurrent包提供的方法,它实现了读操作无锁,写操作则通过操作底层数组的新副本来实现,是一种读写分离的并发策略。我们可以通过以下图示来了解下CopyOnWriteArrayList的具体实现原理。

在这里插入图片描述

回到案例中,我们知道黑名单是一个读远大于写的操作业务,我们可以固定在某一个业务比较空闲的时间点来更新名单。

这种场景对写入数据的实时获取并没有要求,因此我们只需要保证最终能获取到写入数组中的用户ID就可以了,而CopyOnWriteArrayList这种并发数组容器无疑是最适合这类场景的了。

Set体系

1.HashSet

HashSet的contains方法原理:主要就是一个查找过程,底层基于HashMap实现,就是查找哈希桶位,然后再遍历链表(红黑树)查找是否有目标元素。需要注意两点:

  • 重写equals()方法,判断相等的核心依据;
  • 重写hashcode()方法,确保哈希性能;

2.TreeSet

同TreeMap,可自定义排序,红黑树,插入值非空(1.8之后)

二叉树

BST、AVL、红黑树、B树、B+树

经典数据结构问题

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值