一、定义
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
线性表:数据之间只有前后两个方向,数组是线性表,常见的线性表包含:数组、链表、栈、队列等。
非线性表:数据之间不仅仅是简单的前后两个方向。 常见的非线性表:二叉树、堆、图等。
二、特性
1.大多数下标从0开始
因为从零开始所以在计算下标偏移的时候会简单很多,这个下标0其实指的是(当前地址-开始地址)/数据长度,如果从一开始每次还需要再减一,对于底层系统来说多一次数据加减操作就会影响性能。
2.连续的内存空间
3.随机访问:
连续的内存空间能保证通过计算得到数据的地址、数据格式相同保证了数据可读性。
4.删除或者插入较为低效:
因为需要保证数据连续性,所以需要整体挪动数据。当然插入和删除操作也可以适度优化,例如多次操作通过简单的是否连续进行暂存和标记,然后到达一定量之后统一操作,这不就是jvm的复制回收算法吗,了解一个算法的原理和灵活远比死记硬背下来重要的多。
三、常见问题
数组越界:不同语言的数组越界表现不一样
例如c语言中如果访问长度为n的数组的索引n就是arr[n]则返回的是索引的值,原因是当数组申请内存时候,0到n-1的位置存储的数组的数据,n的位置存储的是索引的值。
三、与容器区别
容器与数组相比封装了很多操作细节,并且支持动态扩容。
容器初始化最好设置好存储数据大小,过多的扩容也会影响效率。
日常开发容器方便一些,性能也够用,但是如果开发中间件或者底层等考虑性能的地方就需要注意数组的应用了。
四、常见操作
数据的常见操作无外乎存储和读取以及删除,由于数组是连续的内存空间可以实现数据预读,所以可以高效的查询。
查询:O(1),可以根据下标计算对应读取数据下标直接读取内容
删除和插入(新增):如果不需要整体移动:则O(1),如果需要整体移动(操作的不是末尾元素)则为O(n).