数组的理解
数组的定义
是一种线性表数据结构,是用一组连续的内存空间存储一组具有相同类型的数据。
一般线性表有链表 栈 队列 非线性表有树和图。
数组基于定义就限定了要进行增加和删除操作的时候需要做大量的数据搬移才能保证数组中存储数据的连续性。
但是可以进行随机访问。
计算机要访问具体下表的元素的时候,通过寻址公式计算该元素存储的内存地址,然后根据地址访问对应的内存单元。
注意:数组只有根据下标访问元素的时间复杂度为O(1),通常排好序的数组,用二分查找时间复杂度只能达到O(logn)
数组的插入和删除操作
假设数组的长度为n,我们将数据插入到第k个位置,按照规则就会把k~n的元素往后移一位。
这时候最好情况时间复杂度是O(1),最坏情况时间复杂度是O(n) 平均情况时间复杂度就是 (1+2+3+……+n)/n=O(n)
将数据删除的时候也是和插入一样。
但是针对如此低效的操作 我们可以用一些技巧来提高效率
在插入无序的长度为n数组a的时候,我们需要把x插入到第k个的位置的时候,我们只需要把第k个位置的数据c放到数组的最后
把a[n-1]赋值给c,把a[k-1]赋值给x。
在进行删除的时候,为了避免元素被移动很多次,每次的删除操作不是真正的删除而是标记为已被删除。
当数组中没有更多的存储空间的时候,在集中触发一次真正的删除。
JVM的标记清楚垃圾回收算法也是这种思想。
Java中数组的实现方式
基本数据类型的数组存储的是int char long等基本数据类型
1 int arr[]=new int [3]
2 arr[0]=1
3 arr[1]=1
4 arr[2]=2
new申请的空间在堆上,arr存储在栈上,arr存储的是空间的首地址。arr[i]存储的不是数据本身,并且存储在连续的内存空间
对象数组的区别是,arr[i]存储的不是对象本身,而是对象在内存的地址,对象本身在内存中并不是连续存储的。
ArrayList的优势
把很多数组的操作细节封装起来,插入删除的搬移操作以及动态扩容,虽然都是封装好的但是涉及内存申请和数据搬迁是比较耗时的,最好是创建ArrayLsit事先指定容器大小。
需要注意的是ArrayList的初始化容量已经变了,不再是以前的10了,而是初始化为0,等到第一次add的时候再初始化为10。
ArrayList无法存储基本数据类型,比如int long 需要封装成包装类型,但是自动拆箱和装箱是有一定的性能消耗的。
为什么ArrayList无法存储基本数据类型?
jdk1.8关于ArrayList的源码
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
因为虚拟机在编译的时候要把带泛型的转换为object类型,而基本类型不属于object类型。
Java中的二维数组中的第二维可以是不同长度的。