数组

本文详细介绍了数组这一线性表数据结构,包括数组的定义、线性表与非线性表的区别、数组的随机访问特性、插入和删除操作的时间复杂度分析,以及实际开发中如何选择使用数组或容器。通过对寻址公式的探讨,强调了正确理解数组操作复杂度的重要性,并提出了优化数组操作的策略。
摘要由CSDN通过智能技术生成

1.什么是数组

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

2.线性表与非线性表

线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。

除了数组,还有链表、队列、栈等也是线性表结构。

非线性表比如,二叉树、堆、图等。在非线性表中,数据之间并不是简单的前后关系。

3.数组的特性

随机访问。由于连续的内存空间和相同类型的数据这两个的限制,造就了这个特性。

4.数组的基本操作

4.1 随机访问

4.1.1 例子

以数组 int[] a = new int[10] 来举例。 计算机给数组 a[10],分配了一块连续内存空间 1000~1039,其中,内存块的首地址为 base_address = 1000。如下图:

 

 

计算机会给每个内存单元分配一个地址,通过地址可以访问到内存中的数据。当数组需要随机访问的时候,

首先会根据寻址公式确定地址。然后会根据地址去访问。

 

4.1.2 寻址公式:

一维数组的寻址公式:

a[i]_address = base_address + i * data_type_size

data_type_size 表示数组中元素的大小。比如int类型的数组为4个字节。

 

二维数组的寻址公式:

对于 m * n 的数组,a [ i ][ j ] (i < m,j < n)的地址为:

b[i][j]_address = base_address + ( i * n + j) * data_type_size

 

4.1.3 正确的描述

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

注意:如果不是根据下标随机访问。直接说数组的时间复杂度为 O(1)是不正确的。因为即使为二分查找复杂度也是 O(logn),根本不是 O(1)。

 

4.2 插入操作

4.2.1 数组有序

 

设数组长度为n,插入到数组第k个位置。

如果是数组末插入,直接插入就好,时间复杂度为O(1)。

如果不是在数组末插入,为了腾出第k个位置,就需要把k到n这部分数据向后挪一位。

最坏的情况是数组首位插入,数组的所有数据都要向后移动一位。最坏时间度为O(n)

因为每个位置插入的概率是一样的,所以平均时间复杂度为(1+2+3+...+n)/n = O(n)

 

4.2.2 数组无序

如果数组是无序的情况下,除了上面的做法。为了减少数据大规模搬移。直接将第 k 位的数据搬移到数组元素的最后,把新的元素直接放到第K个位置。

假设数组 a[10] 中存储了如下 5 个元素:a,b,c,d,e。

将元素 x 插入到第 3 个位置c 放入到 a[5],将 a[2] 赋值为 x 即可。如下图:

这样的话,时间复杂度就变为O(1)了

4.3 删除操作

为了保持数组所占内存的连续性。还是需要搬移数据。

删除和插入类似如果删除数组末尾的数据,则最好情况时间复杂度为 O(1);如果删除开头的数据,则最坏情况时间复杂度为 O(n);平均情况时间复杂度也为 O(n)。

某些特殊场景下,并不一定追求数组中数据的连续性。可以把多次删除操作合并成一次。

数组 a[10] 中存储了 8 个元素:a,b,c,d,e,f,g,h。需要依次删除 a,b,c 三个元素。

常规操作的话,是a,b,c分别删除3次,然后,d,e,f,g,h需要搬移3次。

换另外一种方式,a,b,c在删除的时候先做标记,而不是一次性删除。当数组没有足够空间的时候,一次性删除。这样的话就减少了数据的搬移次数。和JVM标记清除垃圾回收算法类似

 

5.数组访问越界的问题

Java 本身就会做越界检查。如果有数组越界的情况,就会抛出 java.lang.ArrayIndexOutOfBoundsException。

 

6.实际开发中数组和容器如何选择

6.1 如果是业务开发。直接用容器。如果已知需要存储数据的大小。在创建容器的时候就指定大小。

比如:

ArrayList<User> users = new ArrayList(10000);

for (int i = 0; i < 10000; ++i) {

users.add(xxx);

}

6.2 如果是基础框架的开发,能用数组还是要用数组。毕竟框架的话更需要考虑性能问题。

 

参考资料:《数据结构与算法之美》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值