1.线性结构
线性结构:数据元素一对一线性关系
有两种不同存储结构:顺序存储结构和链式存储结构
顺序表中的存储元素是连续的
链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息
线性元素举例:一维数组 队列 链表 栈
2非线性结构
二维数组 多维数组 广义表 树结构 图结构
3表
3.1ArrayList
适用 : get set add(val)末端添加 查找 时间复杂度:o(1)
add(0,val)前端添加 remove
当你的操作是在一列 数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能
扩容->add方法的实现
说了这么多,还没有说到无参构造函数默认是空数组,为什么注释说是容量为10的数组,也还没说到当容量不足时,是如何实现动态扩容的,下面就通过add方法来说明这些问题。(add方法是list接口中声明的通用方法)。ArrayList的add方法实现如下:
size是当前集合拥有的元素个数(未算进准备新增的e元素),从源码看出,调用了ensureCapacityInternal来保证容量问题,传进去的参数是size+1,来保证新增元素后容量满足要求。
接下来进入ensureCapacityInternal方法查看其实现:
可以看到代码段:
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
通过这一步来判断,当前elementData是否为空数组(即初始化容量为0或者调用了无参构造函数后的结果),如果是,则使用
Math.max(DEFAULT_CAPACITY, minCapacity)进行选择一个较大的,其中,DEFAULT_CAPACITY是ArrayList定义的静态常量10:
可以看出,这里如果minCapacity小于10的话(如果elementData为空的话,size+1即minCapacity一般为1),返回的是10,所以如果没有指定大小的话,默认是初始化一个容量为10的数组。然后在调用ensureExplicitCapacity方法:
可以看到modCount++,这里可以暂时不管它,这个参数主要是用在集合的Fail-Fast机制(即快速失败机制)的判断中使用的。(以后有空再补充这方面的内容)
在这个方法里进行判断,新增元素后的大小minCapacity是否超过当前集合的容量elementData.length,如果超过,则调用grow方法进行扩容。我们进入该方法进行查看:
在这里可以很清楚的看到扩容容量的计算:int newCapacity = oldCapacity + (oldCapacity >> 1),其中oldCapacity是原来的容量大小,oldCapacity >> 1 为位运算的右移操作,右移一位相当于除以2,所以这句代码就等于int newCapacity = oldCapacity + oldCapacity / 2;即容量扩大为原来的1.5倍(注意我这里使用的是jdk1.8,没记错的话1.7也是一样的),获取newCapacity后再对newCapacity的大小进行判断,如果仍然小于minCapacity,则直接让newCapacity 等于minCapacity,而不再计算1.5倍的扩容。然后还要再进行一步判断,即判断当前新容量是否超过最大的容量 if (new