集合
最佳实践:什么时候使用数组
数据个数和类型确定的场景
最佳实践:什么时候使用集合
数据个数不确定,且要做增删元素的场景
集合分为单列Collection和双列Map,Collection集合体系是什么样的
List集合和Set集合有什么不同点
List:有序,可重复,有索引
- ArrayList
- LinkedList
Set:无序,不重复,无索引 - HashSet
- LinkedHashSet:有序
- TreeSet:按照大小升序排序
集合中是否可以存储基本数据类型,为什么
不可以,只能存储包装类。
集合定义时使用的泛型都只支持引用对象类型,不支持基本数据类型。
Iterator迭代器遍历过程
调用集合的 iterator() 方法,返回一个迭代器,指向集合的第一个元素,默认指向当前集合的索引0
调用 hasNext() 方法时,会验证当前指向的索引是否有值。
调用 nect() 方法,取出当前指向的索引对应的值,然后将指针移到下一个元素。
也就是说,指针一直指向当前元素。
最佳实践:增强 for 循环不能修改原本集合的数据
每次循环时,将数据复制到一个临时的地址中,所以改变元素的值,是不会修改原本集合的数据的。(如果是引用类型,就可以改变)
比如下面,在遍历时将第一个元素改变值
循环开始
取出第一个元素的值,指针向后移动一位
在for循环中将“a”改为"q",只会改变临时变量,修改第三方变量的值不会影响到集合中的元素
二叉树
二叉树有什么特点
- 根节点:有一个根节点
- 度:节点的度不超过2
- 高度:根节点的高度最大
- 层:根节点在第一层
二叉查找树与二叉树有什么不同
每个节点,左子树的值都小于根节点,右子树的值都大于根节点
提高查询的性能
二叉查找树的问题是什么,如何解决
当一边的子树特别长的时候,查询性能就会退化成单链表。为解决这个问题,引入平衡二叉树,让二叉树尽可能矮小,以提升查询性能。
什么是二叉平衡树
任意节点的左右两个子树的高度差不超过1,任意节点的左右两个子树都是一颗平衡二叉树
二叉平衡树添加元素后如何保持平衡
-
左左(根节点左子树的左子树有节点插入,导致二叉树不平衡)
右旋进行平衡
-
左右(根节点左子树的右子树有节点插入,导致二叉树不平衡)
左子树左旋之后,整棵树右旋保持平衡
-
右右(根节点右子树的右子树有节点插入,导致二叉树不平衡)
左旋保持平衡
-
右左(根节点右子树的左子树有节点插入,导致二叉树不平衡)
右子树右旋之后,整棵树左旋保持平衡
红黑树是什么,有什么特点
- 每一个节点或是红色的,或者是黑色的,根节点必须是黑色
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
为什么要用红黑树,而不使用平衡二叉树
虽然平衡树解决了二叉查找树退化为近似链表的缺点,能够把查找时间控制在 O(logn),不过却不是最佳的,因为平衡树要求每个节点的左子树和右子树的高度差至多等于1,这个要求实在是太严了,导致每次进行插入/删除节点的时候,几乎都会破坏平衡树的第二个规则,进而我们都需要通过左旋和右旋来进行调整,使之再次成为一颗符合要求的平衡树。
显然,如果在那种插入、删除很频繁的场景中,平衡树需要频繁着进行调整,这会使平衡树的性能大打折扣,为了解决这个问题,于是有了红黑树。
与平衡树不同的是,红黑树在插入、删除等操作,不会像平衡树那样,频繁着破坏红黑树的规则,所以不需要频繁着调整。
并且同一个元素插入时,红黑树更快!
红黑树加入元素的过程
- 凡是加入元素,都先认为是红色
- 如果是根节点,要改为黑色
- 如果不是根节点,从根节点开始往下比较,放置到某个位置
- 检查父节点和叔叔节点,如果都是红色,和自己相同了,则按照自己的颜色,修改上面的级别的颜色(修改父节点和叔叔节点为黑色、祖父节点为红色等,但不要修改其他父辈节点)
- 然而一直保留根节点为黑色
- 当祖父节点出现失衡,将祖父节点,父节点和自己节点进行旋转,使恢复平衡
LinkedList 底层是基于什么数据结构实现的,导致查询?增删首尾元素?
双链表,慢,快。
list 容量达到最大时是如何扩容的?
原本数组长size,则会再开辟一个 2*size 的数组,把原先数组的数据都复制过去。
从集合中的一批元素中找出某些数据并删除,如何操作?是否存在问题呢 ?
- 当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题
- 迭代器遍历集合且直接用集合删除元素的时候可能出现
- 增强for循环遍历集合且直接用集合删除元素的时候可能出现
- 迭代器遍历集合但是用迭代器自己的删除方法操作可以解决
- 使用for循环遍历并删除元素不会存在这个问题
为什么会出现并发修改异常问题
迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
如何解决
A:迭代器迭代元素,迭代器修改元素
B:集合遍历元素,集合修改元素(普通for)
两者不要交叉
泛型
泛型如何使用
一般使用 E,T,K,V 声明一个泛型
泛型类
public class MyArrayList {}
泛型方法
public void show(T t) {}
泛型接口
public interface Data{}
泛型通配符 ?
?可以用来代指所有泛型
如之前定义的 E,T,K,V
泛型的上下限如何表示
上限:
? extends Car: ?必须是Car或者其子类 泛型上限
? super Car : ?必须是Car或者其父类 泛型下限
最佳实践:同一个方法的参数包括某A类及其子类B时,可以使用泛型
public void function(T param1){}
public void function(T param1){}