目录
数组(Array)是一种线性表数据结构。它利用一组连续的内存空间,来存储一组具有相同类型的数据
数组的随机访问原理:因为内存连续,且存储的数据类型相同,因此可以通过脚标计算出所在位置
数组的插入删除:由于为了保证连续性,就需要做大量的数据搬移工作,所以低效,不保证顺序的时候,可以通过位置交换,提高效率
数组(Array)是一种线性表(数据间是简单的前后关系)数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
一、数组的随机访问原理:
数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)(并不是数组的查找时间复杂度)
根据下标查找元素的原理:
一个长度为 10 的 int 类型的数组 int[] a = new int[10]。在图中,计算机给数组 a[10],分配了一块连续内存空间 1000~1039,其中,内存块的首地址为 base_address = 1000。计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存中的数据。当计算机需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:a[i]_address = base_address + i * data_type_size;int类型数据是4个字节。
二、数组的插入删除:
数组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工作,因为插入和删除操作及其低效。
无序数组中指定位置插入删除数据:
可以采用位置数据交换的办法提高效率,使得在第 k 个位置插入一个元素的时间复杂度就会降为 O(1)。
如果数组中存储的数据并没有任何规律,数组只是被当作一个存储数据的集合。在这种情况下,如果要将某个数据插入到第 k 个位置,为了避免大规模的数据搬移,我们还有一个简单的办法就是,直接将第 k 位的数据搬移到数组元素的最后,把新的元素直接放入第 k 个位置。利用这种处理技巧,在特定场景下,在第 k 个位置插入一个元素的时间复杂度就会降为 O(1)。这个处理思想在快排中也会用到。
删除多元素:
我们继续来看例子。数组 a[10]中存储了 8 个元素:a,b,c,d,e,f,g,h。现在,我们要依次删除 a,b,c 三个元素。
为了避免 d,e,f,g,h 这几个数据会被搬移三次,我们可以先记录下已经删除的数据。每次的删除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。【JVM 标记清除垃圾回收算法的核心思想】
三、容器ArrayList能否完全替代数组?
问题:
在大部分编程语言中,数组都是从 0 开始编号的,但你是否下意识地想过,为什么数组要从 0 开始编号,而不是从 1 开始呢?
从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。如果用 a 来表示数组的首地址,a[0]就是偏移为 0 的位置,也就是首地址,a[k]就表示偏移 k 个 type_size 的位置