你真的了解数组吗?

前言:

数组,应该是我们每个人学习编程时接触的第一个数据结构。它很简单,但是却很重要

为什么这么说呢?

很多高级的数据结构,其实都是由数组组成的,或者说是用数组来实现的。

比如跳跃表、散列表是由数组+链表组成的。

堆、完全二叉树、图(邻接矩阵存储)都可以用数组来实现。

所以说学好数组,就等于为你学习高级的数据结构打下了坚实的基础。

什么是数组?

数组是一种线性表数据结构、它用一组连续的内存空间,来存储一组数据类型相同的数据

这里我们来解释一下什么是线性、连续内存空间存储相同数据类型数据

线性指的是一维存储结构,比如:队列、数组、栈、链表。只有前后两个方向。

而非线性表指的是不仅仅具有前后两个方向的存储结构,比如:树、图、堆等。

因为数组占用的内存空间是连续的,所以它支持随机访问。我们只需要知道数据的存储位置,就可以以O(1)的时间复杂度访问到该元素。

这是如何做到的呢?

首先我们先来看一下在数组是如何存储在内存中的。数据加载到内存中,内存首先会为其分配一个内存空间。计算机通过访问内存空间,来获取元素,这个过程我们称之为寻址。

计算机想要访问数组中的下标值为i的数据,只需要通过下面的寻址公式即可。

a[i]_address = base_address + i * data_type_size(首地址+偏移量*数据大小)

如果数组是一个int型数组,那么data_type_size=4。我们可以通过下标值直接访问到元素,这种访问方式,我们称之为随机访问,它的时间复杂度是 O(1)。

没有最好的数据结构,只有最适合使用它的场景

虽然数组的访问效率很高,但是它的拆入和删除效率却很低,O(n)

这里以插入为例,如果我们想插入一个元素,则需要将插入位置后面的元素依次移动一个位置。

删除元素也是如此。

有没有什么办法可以提升插入与删除元素的效率呢?

针对于插入操作,如果不要求数组内元素有序,那么每次插入操作,我们都可以将插入位置的后一个元素移动到数组末尾,然后在原位置进行插入。

这样也可以达到O(1)的时间复杂度

 

 

 针对于删除操作,我们在删除数据的时候,可以先为被删除元素打上标记,等到数组中元素已满,再统一进行删除(JVM标记清除算法)。或者当有插入操作的时候,优先使用被标记元素的内存(Mysql中delete操作)。

 

 

 

集合是否能代替数组呢?

答案是否定的,没有最好的数据结构,只有最适合使用的场景。

集合可以看作是一个动态数组(可扩容),底层其实也是一个数组。

下面这些场景中,我们还是更推荐使用数组:

    1. 表示多维数据的时候,在可读性上,数组优于集合。(int arr[][]; ArrayList<ArrayList<Integer>>)
    2. 在性能要求极高的场景中,我们使用数组可以避免自动拆箱、装箱的性能损耗。
    3. 再简单的场景中,使用数组会比使用集合具有更高的可读性。

 

posted @ 2019-12-03 22:27  进击的李同学  阅读(286)  评论(0编辑  收藏  举报