ArrayList和LinkedList特点及各自应用场景
底层数据结构: Arraylist 底层使⽤的是 Object 数组;LinkedList 底层使⽤的是 双向链表 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。)
插入和删除: Arraylist 在内存中是一块连续的内存,如果插入或删除时需要移动内存。LinkedList 插入时不需要移动内存,只需要改变引用指向即可。
随机访问: Arraylist支持随机访问,LinkedList不支持随机访问。
应用场景: Arraylist适合查询较多的场景,因为支持随机访问,查询快。LinkedList适合插入、删除频繁的场景,因为删除插入操作简单,而查询需要遍历链表。
TreeMap和LinkedHashMap
LinkedHashMap
底层数据结构: LinkedHashMap是在hashmap结构的基础上,增加了⼀条双向链表,使得上⾯的结构可以保持键值对的插⼊顺序。同时通过对链表进行相应的操作,实现了访问
顺序相关逻辑。
特点与应用场景:
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历的时候会比HashMap慢。
TreeMap
https://blog.csdn.net/weixin_34384681/article/details/92004747
底层数据结构: TreeMap实现了SortMap。TreeMap 底层结构为红黑树,红黑树的Node排序是根据Key进行比较。每次新增删除节点,都可能导致红黑树的重排。
特点与应用场景: TreeMap能够根据键排序,默认是按升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。 因为数据结构是红黑树,所以增删改查的时间按复杂是O(logn)。
ConcurrentHashMap怎么取的size值
https://blog.csdn.net/ff00yo/article/details/89439512
https://blog.csdn.net/qian_348840260/article/details/47105575
在 JDK1.7 中,第一种方案在不加锁的模式下,统计所有Segment里元素的大小后求和,最多三次,比较前后两次计算的结果,结果一致就认为当前没有元素加入,计算的结果是准确的。 第二种方案是如果第一种方案不符合,他就会给每个 Segment 加上锁,然后计算 ConcurrentHashMap 的 size 返回。
那么ConcurrentHashMap是如何判断在统计的时候容器是否发生了变化呢?使用modCount变量,在put , remove和clean方法里操作元素前都会将变量modCount进行加1,那么在统计size前后比较modCount是否发生变化,从而得知容器的大小是否发生变化。
跳跃表Zset
https://blog.csdn.net/zy450271923/article/details/106970148
它其实是一种随机化的数据结构,一个多层的有序链表,一种基于概率统计的插入算法。
redis中的zset为什么不使用红黑树而使用跳跃表
- 首先,在做范围查询的时候,平衡树的操作要比跳跃表复杂。因为平衡树,在查询到最小值的时候,还需要采用中序遍历去查询最大值。 而skipList只需要在找到最小值后,对第一层的链表(也就是最底层的链表)进行若干次遍历即可。
- 平衡树的删除和插入,需要对子树进行相应的调整,操作复杂。而skiplist只需要修改相邻的节点即可。
- 在做查询操作的时候,skiplist和平衡树都是O(logN)的时间复杂度。
- 从整体上来看,skiplist算法实现的难度要低于平衡树。
跳跃表的实现原理
跳跃表就好像每两个元素抽取一个元素放到上一层,这样一次叠加,就形成了多层的链表。上一层的元素个数是下一层元素个数的1/2,所以查询的时候就类似二分查找。
这种方法类似于二分查找的方法,所以跳跃表的查找的时间复杂度为O(logN)