数组是由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识。
数组内的元素是连续存储的,所以数组中元素的地址,可以通过其索引计算出来
空间占用
Java 中数组结构为
-
8 字节 markword
-
4 字节 class 指针(压缩 class 指针的情况)
-
4 字节 数组大小(决定了数组最大容量是 2^32)
-
数组元素 + 对齐字节(java 中所有对象大小都是 8 字节的整数倍12,不足的要用对齐字节补足)
以下是动态数组的实现:
public class DynamicArray implements Iterable<Integer>{//逻辑大小private int size=0;//容量private int capacity=10;private int[] array;//数组尾部添加元素public void add(int element){add(size,element);}/***添加元素* @param index 向指定索引出添加数据* @param element 添加元素*/private void add(int index, int element) {//插入数据前对数组进行检查checkAndGrow();if(index>=capacity){throw new RuntimeException("索引越界");}if(index>=0 && index <size){System.arraycopy(array,index,array,index+1,size-index);}array[index]=element;size++;}/*** 检查数组大小* 若size==capacity则进行扩容*/public void checkAndGrow(){if(size==0){//初始化数组array=new int[capacity];}else if(size==capacity){//进行扩容,规则:当前容量+当前容量/2capacity +=capacity>>1;//创建新的数组int[] newArray=new int[capacity];System.arraycopy(array,0,newArray,0,size);//赋给原数组array=newArray;}}/***删除元素* @param index 索引位置* @return 被删除元素*/public int remove(int index){if(index>=capacity){throw new RuntimeException("索引越界");}int removed=array[index];if(index<size-1){System.arraycopy(array,index+1,array,index,size-index-1);}size--;return removed;}/*** 查询元素* @param index 索引位置, 在 [0..size) 区间内* @return 该索引位置的元素*/public int get(int index){return array[index];}/*** 遍历方法1* @param consumer 遍历要执行的操作, 入参: 每个元素*/public void foreach(Consumer<Integer> consumer){for (int i = 0; i < size; i++) {// 提供 array[i]// 返回 voiconsumer.accept(array[i]);}}/*** 遍历方法2 - 迭代器遍历*/@Overridepublic Iterator<Integer> iterator() {return new Iterator<Integer>() {int i = 0;@Overridepublic boolean hasNext() { // 有没有下一个元素return i < size;}@Overridepublic Integer next() { // 返回当前元素,并移动到下一个元素return array[i++];}};}/*** 遍历方法3 - stream 遍历** @return stream 流*/public IntStream stream(){return IntStream.of(Arrays.copyOfRange(array, 0, size));}
}
插入或删除性能
头部位置,时间复杂度是 O(n)
中间位置,时间复杂度是 O(n)
尾部位置,时间复杂度是 O(1)(均摊来说)