1.数组概念:是一种线性表结构。用一组连续的内存空间来存储一组具有相同类型的数据。
2.例:int [ ] a = new int[10]
计算机给数组a分配了一段连续的内存空间1000——1039,内存块首地址base_address = 1000。
计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存中的数据,当随机访问数组中某个元素时,先通过寻址地址计算出该元素的内存地址:
a[i]_address = base_address + i * data_type_size
data_type_size : 数组中每个元素的大小,即数组中元素的数据类型的大小。
比如我们想访问a[3],那么a[3]_address = 1000+3*4 = 1012
3.数组支持随机访问,根据下标随机访问的时间复杂度为O(1);
排好序的数组通过二分查找,时间复杂度为O(log n)。
4.插入操作
假设数组长度为n,插入一个元素到数组的第k个位置
(1)数组中数据有序:直接在末尾插入,时间复杂度O(1);在开头插入,所有元素依次后移一位,时间复杂度为O(n)。在每个位置插入的可能性都是一样的,为1/n,平均时间复杂度为1*1/n+2*1/n+...+n*1/n = O(n);
(2)数组中数据无序:直接将第k位的数据搬移到末尾,把新元素放到第k个位置。正常情况下,第k个位置插入一个元素的时间复杂度为O(1).
5.删除操作
同插入类似,删除一个元素,这个位置后面的元素前移。平均时间复杂度O(n)。
6.容器与数组
ArrayList:可以将很多数组操作的细节封装起来、支持动态扩容(存储空间不够时,自动将空间扩容为原来的1.5倍。扩容操作涉及内存申请和数据搬移,所以创建ArrayList时最好事先指定数据大小)。
数组:假设定义数组时指定大小为10,当插入第11个元素时,要重新分配一块更大的空间,将原来的数据复制过去,然后再将新的数据插入。
适合用数组的情况:
(1)ArrayList无法存储基本类型,比如int/long要封装为Integer/Long类,但装箱、拆箱操作会有性能消耗,所以如果关注性能或想使用基本类型,要用数组。
(2)如果数据大小已知,并且对数据的操作比较简单,使用数组。
(3)表示多维数组时,数组更直观Object[][] arr;容器则要表示为ArrayList<ArrayList<Object>> arr。
7.寻址公式
一维:a[i]_address = base_address + i * data_type_size
二维数组大小:m*n
二维:a[i][j]_address = base_address + (i*n+j)*data_type
参考:王铮《数据结构与算法之美》