1001:数组

总结

一、什么是数组?

1.定义

数组是一种线性表,它用连续的内存空间来存储多个相同数据类型的数据。怎么理解这个定义?主要从线性表、连续内存和相同数据类型三个关键词来看。

2.什么是线性表?

顾名思义,数据就像一条直线一样进行组织,每一个数据都只有前后两个方向,除了数组之外,队列、栈、链表也都是线性表。与线性表相对应的就是非线性表,比如树、图等。

3.连续内存和相同数据类型的限制有什么影响?

正是由于这两个限制,才有了数组的杀手锏:O(1)级别随机访问,但与此同时也造成了其他一些操作的低效,比如O(n)级别随机插入、删除操作。为什么?看下面数组的特点。

二、为什么使用数组?即数组的特点:擅长随机访问,但不擅长随机插入、删除操作

1.数组如何实现高效随机访问?

1)数组根据寻址公式获得数据的存储位置,然后直接访问该位置的数据,这是O(1)级别的时间复杂度。

2)寻址公式:a[ i ]_address = base_address + i * data_type_size,其中a[ i ]_address表示数组第i+1个元素下标值,base_address表示数组的起始地址, data_type_size表示数据类型占用存储空间大小。

3)例子:int[ ] a = new int[10]; 要获得下标值为2的元素,则其地址就是a[ 2 ]_address = base_address + 2 * 4,其中int类型数据占用4个字节的内存空间。

2.为什么数组随机插入、删除操作低效?如何优化?

1)为了保证数组中数据存储空间的连续性,在指定位置插入或删除元素时,需要将该位置及其后面的数据整体移动(插入则是后移,删除则是前移),这会产生O(n)级别的时间复杂度。

2)随机插入

以int[ ] a = new int[n]为例,向a数组指定下标值处插入元素,根据具体的位置不同有n中情况,每种情况出现的概率都是1/n。比如在末尾插入,则时间复杂度为O(1),在首位置插入元素,则时间复杂度为O(n),按照平均复杂度计算方式,在a数组中随机插入一个数据的平均复杂度为1/n*1+1/n*2+…+1/n*n = O(n)。所以,数组随机插入的平均时间复杂度是O(n)级别。

如何优化呢?这里分为2种情况,即数组中数据有序还是无序。若数组中的数据需保持有序,那没办法还得一个一个的移动数据,O(n)级别的时间复杂度;若数组中的数据不要求有序,仅仅作为存储数据的容器,那就好办了,可以把插入位置的旧数据先移动到末尾位置,再把新数据插入进去,这下平均时间复杂度就变为O(1)级别了。

3)随机删除

按照正常的逻辑,我们每删除一个数据,就必须向前移动部分其他数据以保证数据存储空间的连续性,这就是O(n)级别的时间复杂度。

如何优化呢?在特殊情况下,比如删除多个连续位置的数据,可以将操作合并,只整体移动一次数据,而不是每删除一次就移动一次或者当我们并不要求数据空间一定连续时,执行删除操作时并不真正删除而是先标记该数据无效即可,当数组空间不足时,再一次性删除和移动数据,这也是JVM垃圾回收器算法的核心精髓。这些都能在一定程度上提升随机删除的效率。

三、数组的注意事项有哪些?

使用数组的过程中最常见的错误就是数组下标越界,在Java语言中,编译器会自动判断,若下标越界则编译不通过。

四、数组和ArrayList集合的区别是什么?(面试常问)

1.ArrayList集合是什么?

ArrayList对数组的操作细节(比如插入、删除时的数据移动,还有就是1.5倍自动扩容)进行了封装。

2.ArrayList集合性能消耗

在自动扩容时有申请内存空间和复制整份数据的性能消耗。所以,若能确定数据规模则最好指定ArrayList集合的容量,这样就能避免自动扩容带来的性能消耗。

3.数组和ArrayList集合如何选择?

1)数组能够存储基本类型和引用类型,集合只能引用类型,因此集合存储基本类型会发生自动装箱或拆箱,这会有一定的性能消耗。如果对性能要求特别高,可以考虑选择数组。

2)如果数据大小已知且用不到大多数集合方法时,可以考虑选择数组。

3)进行业务开发时可以选择集合以提升开发效率,而进行底层开发时,比如开发网络框架,性能优化需要做大极致,这时数组就会优于集合。

五、扩展知识点

1.为什么数组下标从0开始?

因为数组的首地址是数组第1个元素存储空间的起始位置,若用下标0标记第1元素则通过寻址公式计算地址时直接使用下标值计算,即a[0]_address = base_address + 0 * data_type_size。若用下标1标记第1个元素则通过寻址公式计算地址时需将下标值减1再计算,即a[1]_address = base_address + (1-1) * data_type_size,这样每次寻址计算都多了一步减法操作,增加了性能开销。

2.多维数组如何寻址?

这个在Java中没有意义,因为Java中多维数组的内存空间是不连续的,所以,暂不考虑。

3.JVM垃圾回收器算法的核心精髓是什么?

若堆中的对象没有被引用,则其就被JVM标记为垃圾但并没有释放内存空间,当数组空间不足时,再一次性释放被标记的对象的内存空间,这就是JVM垃圾回收器算法的核心精髓。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值