ArrayList:源码难点 扩容和缩容 存放元素:有序 线程是否安全:不安全 核心方法:get(下标查询) add 底层数据结构:数组基于object类型
时间复杂度的原因 O(1) O(n) O(lgn) 基于下标查询就是O(1) 基于元素值查询就是O(n)-----链表
private void ensureExplicitCapacity(int minCapacity) {
// 线程同步,不能在遍历的时候进行添加或者删除操作
modCount++;
// 判断是否需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// 初始化容量为0
int oldCapacity = elementData.length;
// 新的容量还是为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
// 新的容量为10,只有第一次初始化会走这个判断
newCapacity = minCapacity;
// 这个判断正常不会走
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
每次扩容,容量增加1.5倍
注意hashmap集合没有缩容,因为缩容需要重新计算index值 基于value值删除复杂度为O(n),需要考虑缩容问题
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
// 线程同步,不能在遍历的时候进行添加或者删除操作
modCount++;
// 计算删除index后面的所有元素有多少个
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
Object src:原数组 int srcPos:从元数据的起始位置开始 Object dest:目标数组 int destPos:从目标数组的开始起始位置 int length:要copy的数组长度
相同点:都是基于数组实现,默认初始容量为10 不同点:
HashSet:基于HashMap实现
思考点: HashSet为什么是无序的?因为HashMap的key不允许重复 hash+equals,hash值排 序 HashSet底层数据结构模型:基于hashmap实现,key为hashset存放的元素,value是空值 缺点:比较占用内存
底层基于双向链表结构实现 查询的时间复杂度为O(n)
为什么需要一个变量记录头结点? 为了后期遍历数据知道从哪里开始!