数组

数组:是一种线性表数据结构,用一组连续存储空间,存储相同类型的数据。java

线性表

数据排成一条线同样的存储结构,在线性表中,数据之间相互关系只有先后关系,除了数组以外,还有链表、队列、栈等。算法

与线性表对应的就是非线性表结构,数据之间不止简单的先后关系,好比:二叉树、堆、图等。数组

连续存储空间和相同类型的数据

数组不只要在逻辑上连续,也要在物理上连续。在内存中就要求必须是连续存储,从而致使数组在新增或删除一个数据的时候,为了保证连续性,就须要作大量数据搬移操做。数据结构

同时数组也具备"随机访问"特性,能够根据下标直接访问数据中的数据。计算机会给每块内存分配地址,经过寻址公式计算出内存地址,就能够直接访问。性能

这个公式也能够解释下为何数组下标是从0开始的?优化

//base_address为首地址,i为数组下标,data_type_size为数组中每一个元素所占大小
a[i]_address = base_address + i * data_type_size

数组操做

理解误区

“数组适合查找,查找操做的时间复杂度为O(1)”,这句话表达不够准确,数组更加适合查找操做,可是查找的时间复杂度并不为O(1),即便排好序的数组,使用二分查找时间复杂度也为O(logn),数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。code

插入操做

假设一个数组长度为n,将一个数据插入到第k个位置,就须要将k到n的数据所有日后移一位,这样最好的时间复杂度为O(1),最坏时间复杂度为O(n),平均时间复杂度为O(n)。队列

若是数组中数据有序,插入新数据就须要按照刚才的方法;若是数据无序,则能够进行优化,最简单的办法就是直接将第k位数据搬移到数组最后,将新元素直接放入第k位。内存

删除操做

删除和插入同样,为了保持连续性,须要进行搬移数据,最好的时间复杂度为O(1),最坏时间复杂度为O(n),平均时间复杂度为O(n)。ci

优化:在特殊场景下,能够将屡次删除操做集中一块儿进行,能够先记录下已经删除的数据。每次的删除操做并非真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,咱们再触发执行一次真正的删除操做,这样就大大减小了删除操做致使的数据搬移。(JVM 标记清除垃圾回收算法的核心思想)

ArrayIndexOutOfBoundsException

Java 自己就会作越界检查,数组下标越界就会抛出 java.lang.ArrayIndexOutOfBoundsException。

总结

  1. Java ArrayList 没法存储基本类型,好比 int、long,须要封装为 Integer、Long 类,而 Autoboxing、Unboxing 则有必定的性能消耗,因此若是特别关注性能,或者但愿使用基本类型,就能够选用数组。
  2. 若是数据大小事先已知,而且对数据的操做很是简单,用不到 ArrayList 提供的大部分方法,也能够直接使用数组。
  3. 还有一个是我我的的喜爱,当要表示多维数组时,用数组每每会更加直观。好比 Object[][] array;而用容器的话则须要这样定义:ArrayList > array。

补充

数组拷贝复制、扩容

//扩容
newElementData = Arrays.copyOf(oldElementData, newCapacity);

//复制
System.arraycopy(被复制的数组A, 从A哪一个下标开始复制, 复制到哪一个数组B, 复制到B从哪一个下标开始, 复制长度);
//实现元素右移
System.arraycopy(elementData, index, elementData, index + 1, size - index);
相关文章
相关标签/搜索