ArrayList
底层:在构造一个包含指定元素的列表初始化方法中,1.8中Collection转换Object[]时会有问题 可能出现转换出来不是Object[]类型,因为每个集合的toArray方法都不一样,所以需要和elementData数组进行对比是否为Object[],如果不是Object[],则需要copyOf进行数组转换,底层实际上用了system.arraycopy方法转换数组
如果没有任何参数 则初始化一个长度为10的数组
扩容:添加的时候进行添加末尾,进行size+1,如果数组为空的话,minCapacity(最小容量)就等于size+1,就等于1,空的数组放不了数据,然后就通过max方法进行默认容量和minCapacity进行大小比较取最大值,所以就将minCapacity变为10,初始容量就是10,默认大小,然后第一次进来初始容量是10,再之后进来需要的容量大于10,开始扩容,扩容时新数组的大小=老数组的大小+老数组大小>>1(将老数组大小向右移动一位,获得老数组大小的一半),相当于1.5倍扩容,进行各种判断
failFast机制:创建迭代对象时将全局的modCount赋值给迭代器的局部变量expectedModCount,在迭代的过程中,modCount!=expectedModCount迅速抛出异常。
原理:同时两个线程执行,a线程执行add方法,b线程执行迭代查询方法,调用next方法,在b线程查询的一瞬间初始化迭代器的时候,比如初始化的expectedModCount为值为8,但是此时a线程也在进行add添加方法,add的时候会对modCount进行++操作,modCount和expectedModCount的两个变量的值就不一样,导致了failFast机制。因为ArrayList是线程不安全的,所以会出现这种问题,解决办法呢就是使用Collections工具类中的synchronizeLIst方法进行同步处理,变为线程安全的
单向链表
单项链表只可以从前往后找,最前面为一个虚拟空节点,为了使得插入第一条数据不用去判断他是不是头节点,添加的时候比如在索引2的位置插入node值100,就可以用prev.next(prev表示索引位2的前一个索引位)指向这个node节点,node.next(node表示要插入的索引值)指向原先prev.next指向的位置,就可以得出node.next=prev.next prev.next=node
删除节点的时候,需要找到要删除节点的前一个节点prev,要删除的节点为delNode,需要prev.next指向delNode.next指向的位置,就是删除节点的下一个节点,最后要把delNode赋值null,让gc进行回收,得出
prev.next=delNode.next delNode=null,注意一点就是不能直接把delNode直接指向delNode.next即delNode=delNode.next,导致delNode无法删除
双向链表
LinkedList就是基于双向链表进行的,除了继承list,还会实现一个队列,add方法有两种方式,
1、add方法中的linkLast:表示向尾部去加数据
三个构造参数l表示指向的前一个节点,e表示当前加入的节点,next指向的是下一个节点,因为是在尾部加数据,所以指向的下一个节点为null
2、push中的linkFirst:表示向头部去添加数据
prev跟上面一样指向前一个节点,因为这个方法是向头部添加,所以当前添加的位置就是头部,前面没有任何的节点,e表示当前添加的数据节点,f表示当前数据的下一个节点位置
树
二叉树
概念:每个节点最多只能有两个子节点,子节点分为左节点和右节点
满二叉树
条件:所有非叶子节点都存在左子树和右子树,并且所有叶子都在最后一层的二叉树
叶子节点只能在最后一层、非叶子节点的度一定是2、同样深度的二叉树中,满二叉树的节点个数最多,叶子树最多
完全二叉树
条件:如过该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续
二叉搜索树--BST
也叫二叉排序树,任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大,如果相同的值,可以将该节点放在左子节点或右子节点
二叉搜索树的深度优先遍历分为:前序遍历,中序遍历,后序遍历
前序遍历:先输出父节点,在遍历左子树和右子树
中序遍历:先遍历左子树,在输出父节点,在遍历右子树,中序遍历的结果是有序的
后序遍历:先遍历左子树,在遍历右子树,最后输出父节点
二叉搜索树的问题:
比如数据(1,2,3,4,5,6),创建BST
-
左子树全部为空,更像一个单链表
-
插入速度没有影响
-
查询速度明显降低
-
解决方案是平衡二叉树
平衡二叉树--AVL
也叫平衡二叉搜索树,必须满足BST的特征
任意一个节点,平衡因子的绝对值不超过1
-
某节点的高度值=max(左子树高度,右子树高度)+1
-
每个节点的左子树和右子树的高度差叫做平衡因子(左右子树高度差为:左子树高度和右子树高度两边值的差不大于1)
因为计算平衡因子出现2,大于了1,所以要经过右旋和左旋来解决不平衡问题
右旋过程:ps:左旋同理
R.right=N N.left=T3 R=root(根节点)
缺点:当频繁的去插入和删除的时候,AVL性能就大大折扣,效率比较低,出现在左右旋的时候,每个节点也只能存一个数据,对节点的利用率差
红黑树
前提:研究红黑树时叶子节点指的是最后的空节点(我们原来理解的叶子节点的孩子节点),就是每个叶子节点下面分别指的左右nil空节点
根节点是黑色的、每个叶子节点都是黑色的(红色节点向左倾斜叫做左倾红黑树)、如果一个节点是红色的,那么他的孩子节点都是黑色的、从任何一个节点到叶子节点,经过的黑色节点个数是一样的
2-3树
-
每个节点都是可以存放一个元素或者两个元素
-
存放一个元素的节点称为2-节点,存放两个元素的称为3-节点
-
每个节点有两个或三个元素的树称为2-3树,2-3树满足二叉搜索树的基本性质
-
2-3树是绝对平衡的树
前提:满足二叉搜索树的特征、维持绝对平衡、不能往null节点插入数据
添加2-3树的规律:如上图,原刚开始添加为42,出现一个一元素二节点,再添加一个50,出现一个二元素三节点,并且42和50是在同一行,因为元素不能往null节点插入,因为42左右子节点都是空,所以50放到42右边,紧接着再放入一个33,33比42小,所以放在42左边,此时为一个三元素四节点,2-3树每个节点只可以存放一个或两个元素,此时为三个元素,所以要开始分裂,最后分裂为二叉搜索树形式,分别将33和50放到42的左右节点,以此类推往后接着放元素,进行添加、分裂,维持平衡
-
2-3树中添加一个新元素,或者添加到2-节点或者添加到3-节点
-
添加到2-节点,形成一个3-节点
-
添加到3-节点,暂时形成一个4-节点,然后把4节点进行分裂
-
如果待融合的节点是3-节点的叶子节点,父节点是2-节点,那么插入的时候要保持绝对平衡,在插入左边的3-节点时称为了四节点,此时要分裂,然后出现不平衡,然后需要吧开始分裂的节点进行融合包吃绝对平衡,下图
-
如果待融入的节点是3-节点的叶子节点,父节点也是3-节点,则需要分裂、融合、分裂,直到平衡为止,下图
2-3树和红黑树等价性,看三张图的变化过程
2-3树格式
2-3树演变红黑树(半)
完整左倾红黑树形式