java容器-技术点汇总

java容器继承图

ArrayList

arraylist的数据结构

数组

arraylist的扩容与缩容

数组容量满时会进行扩容,算法:newCapacity = oldCapacity + (oldCapacity >> 1),扩容为不超过原来的1.5倍:

  • 尾端插入:arraylist通过Arrays.copyOf(oldarray,newCap)对数组进行扩容,并对新的下标进行赋值
  • 中间插入:通过System.arraycopy(elementData, index, elementData, index + 1, size - index);对扩容后的数组进行数据移动,然后对移动后空出来的下标位置进行赋值
  • 删除:System.arraycopy(elementData, index+1, elementData, index, size - index - 1;)进行删除时的缩容,并对尾端置空便于垃圾清理

LinkedList

linkedlist的数据结构

双向链表

arraylist和linkedlist的区别

arraylist底层实现为数组,查找元素属于随机查找,时间复杂度O(1),插入删除时间复杂度为O(n),n为操作下标距数组尾部的长度
linkedlist底层实现为链表,头尾部增加删除效率为O(1),查找时间复杂度为O(n),n为距头部的距离
所以arraylist适合查询多的场合,linkedlist适合头尾节点增加删除较多的场合

arraylist和linkedlist是线程安全的吗

不是线程安全的,线程安全可以使用vector,vector底层实现也是数组,并对相关方法都进行了同步操作

Hashmap

hashmap的数据结构:

数组+单向链表+红黑树

hashmap的链表的树化与链化:
  • hashmap链表的树化界限为8,当桶内元素个数大于8时,会触发树化操作,树化时会检查当前表(table,指数组)的长度是否大于64,若小于64,则用扩容代替树化,大于64,则转化为红黑树。
    树化生成的TreeNode节点保存有链表指针(prev,next),确保需要的时候能够正确的链表化
  • hashmap在删除元素时可能导致桶内元素个数小于6,此时触发链表化,由红黑树转化为单向链表
hashmap的扩容

HashMap在扩容时,需要先创建一个新数组,然后再将旧数组中的数据转移到新数组上来
此时,旧数组上的数据就会根据(e.hash & oldCap) 是否等于0这个算法,被很巧妙地分为2类:
① 等于0时,则将该节点放到新数组时的索引位置等于其在旧数组时的索引位置,记为低位区链表lo开头-low;
② 不等于0时,则将该节点放到新数组时的索引位置等于其在旧数组时的索引位置再加上旧数组长度,记为高位区链表hi开头high
所以,

  1. hashmap在扩容时是对所有元素进行了重新定位,元素要么保持在原索引位置,要么转移到值为原索引位置+原数组长度的新位置
  2. 每次扩容容量变为原来的2倍,阈值也相应变为2倍
  3. JDK1.7扩容时使用头插法,会存在死循环问题,1.8采用尾插法,但hashmap多线程操作时仍存在节点丢失的问题
hashmap的取模算法

快速取模算法:被除数&(除数-1) 除数必须为2的n次方
e.hash & cap -1

hashmap的容量为什么是2的n次方

能够利用位运算加快算法速度

hashmap支持缩容吗

不支持,扩容缩容是比较耗时的操作,没有必要在删除时做缩容操作增加时间复杂度(空间换时间)

hashmap如何减少哈希碰撞

高低16位异或

TreeMap

treeMap的数据结构

红黑树

为什么使用红黑树,红黑树的特点

红黑树天然有序,且插入删除效率比AVL树高

树型结构

树的分类

二叉搜索树
平衡二叉搜索树(AVL树-绝对平衡)
红黑树(相对平衡二叉搜索树)
B树(B-树,多路平衡搜索树)
B+树 (叶节点带有顺序指针的B树)
B*树(节点初始容量增加、元素扩散)

红黑树
  1. 节点有红黑色之分
  2. 根节点和叶子节点必为黑色
  3. 从任一节点出发到叶子节点都包含相同数量的黑色节点
  4. 红色节点不可连续

3,4保证了红黑树的深度差不能超过2倍(红黑交替出现为2倍),相比于AVL树,由于允许一定的深度差,插入删除时的旋转次数少、效率高,相对而言查找效率不如AVL树稳定,在java中应用于线程安全的场合减少并发插入删除时的锁等待

B树相对二叉树的优缺点(索引为什么使用B树)
  1. 首先,对于索引树来说,根节点常驻内存
  2. 一般来说,索引本身很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上,因此磁盘io是索引查找性能的一个瓶颈点
  3. B树每个节点的关键字更多(索引每个节点申请一个数据页的大小,能够存储大量关键字),相比二叉树相同元素数量下树深度非常小,所以能够减少io次数
  4. 另外,由于存在局部性原理磁盘预读(每次io读取多个数据页的内容),范围查找的效率更高(AVL树或红黑树中数值相近的节点在逻辑上可能相差很远,无法利用局部性)
  • 局部性原理:
    • 当一个数据被用到时,其附近的数据也通常会马上被使用
    • 程序运行期间所需要的数据通常比较集中
B树
  • 规则(设定m为B树的最大分叉树或者叫最大子节点数)
    • 节点关键字按递增次序排列,左小右大
    • 枝节点的关键字数量满足 :ceil(m/2) <=关键字数量<=m-1,高于上限抽取出上级节点,低于下限会进行节点合并(从下级节点、上级节点抓取关键字)
    • 所有叶子节点都在同一层,所以B树是绝对平衡树
B+树
  • 有两种节点实现
    • 1.关键字数=子节点数 【ceil(m/2) <=关键字数量<=m 】myslq B+树的实现方式
    • 2.关键字数=子节点数-1

B+树是对B树的优化版,相对于B树:

  1. 非叶子节点不保存数据,只有关键字没有指针,所以每个节点能够保存更多的关键字,树的深度相对更小
  2. 叶子节点保存了所有关键字的指针,所有所有查询都必须到叶子节点,查询速度稳定
  3. 所有相邻数据都在叶子节点内,范围查找效率更高,缓存命中率高
  4. 叶子节点之间保存有指向下一节点的指针,全表扫描更快

附言:B树的优点是如果经常访问的数据离根节点比较近,那么效率会比较高

B*树
  • B*树是B+树的变种,对B+树的一些细节进行了优化
    • ceil(m*2/3) <=关键字数量<=m,初始化下限更高,要求节点拥有更多的关键字数
    • 节点满时不会先分裂,而会检测兄弟节点是否可供转移,如果兄弟节点已满,会抽取当前节点和兄弟节点各1/3数据组建新的节点。相对来讲,节点分解次数变少,节点利用率更高
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值