数据结构与算法系列4--数组

什么是数组?

数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。数组的一个最大特性就是支持下标随机访问数组元素。
补充:
线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。其实除了数组,链表、队列、栈等也是线性表结构。
而与它相对立的概念是非线性表,比如二叉树、堆、图等。之所以叫非线性,是因为,在非线性表中,数据之间并不是简单的前后关系。

数组是如何实现根据下标随机访问数组元素的?

我们拿一个长度为 10 的 int 类型的数组 int[] a = new int[10] 来举例。我们在声明此数组时,计算机会给我们分配好一块连续的内存空间,这里我们假设分配的地址是1000~1039,而此时a存放的就是内存块的首地址 base_address = 1000这个地址,那具体怎么根据下标访问元素呢?
当计算机需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:

a[i]_address = base_address + i * data_type_size

其中 data_type_size 表示数组中每个元素的大小。我们举的这个例子里,数组中存储的是 int 类型数据,所以 data_type_size 就为 4 个字节。通过这个公式,我们就可以根据下标值计算出每个元素的存放的地址,进而拿到该数据,如我们访问a[0],即为访问首地址下的元素,其他的以此类推。

数组的优点

支持随机访问,根据下标随机访问的时间复杂度为 O(1)。所以数组适合查找。

数组的缺点

插入和删除慢,时间复杂度为O(n)。这点刚好和链表相反,链表的插入和删除快,时间复杂度为O(1)。

为何数组插入和删除低效?

插入:
若有一元素想往int[n]的第k个位置插入数据,需要在k-n的位置往后移。
最好情况时间复杂度 O(1)
最坏情况复杂度为O(n)
平均负责度为O(n)
删除:
与插入类似,为了保持内存的连续性。
最好情况时间复杂度 O(1)
最坏情况复杂度为O(n)
平均负责度为O(n)

如何对数组插入和删除操作进行优化?

插入优化:如果数组中储存的数据不是有序的,也就是无规律的情况下,假设要在第k个位置插入数据,则可以将第k个位置的数据移到最后,然后将数据直接插入在第K个位置上。这样时间复杂度就将为 O(1)了。
**删除优化:**将多次删除操作集中在一起执行,对要删除的数据可以先记录下来,不是马上删除,而仅仅是记录,只有当没有更多的储存空间时,再执行真正的删除操作。这也是 JVM 标记清除垃圾回收算法的核心思想。

容器和数组的选择?

数组先指定了空间大小
容器如ArrayList可以动态扩容。
1.希望存储基本类型数据,可以用数组
2.事先知道数据大小,并且操作简单,可以用数组
3.对于业务开发,直接使用容器就足够了,省时省力。毕竟损耗一丢丢性能,完全不会影响到系统整体的性能。但如果你是做一些非常底层的开发,比如开发网络框架,性能的优化需要做到极致,这个时候数组就会优于容器,成为首选。

为什么数组要从 0 开始编号?

由于数组是通过寻址公式,计算出该元素存储的内存地址:
a[i]_address = base_address + i * data_type_size
如果数组是从 1 开始计数,那么就会变成:
a[i]_address = base_address + (i-1)* data_type_size
这样对于CPU来说,就多了一次减法的指令。为了尽可能的快,所以不采取这种方式。

猜你喜欢

转载自blog.csdn.net/qq_34493908/article/details/83004194