穿越到修仙界,筑基功法居然是数据结构(3)——数组(下)

前言

希望基于此系列文章能以轻松,简单的方式帮助大家学习并使用数据结构。

今天进入编程修仙第三期,炼气一层,数组(下),数组的基本概念和思想在上次文章中已经详细介绍,有感兴趣的同学可以跳转查看穿越到修仙界,筑基功法居然是数据结构(2)——数组(上)。本篇将介绍数组的使用。

什么时候使用数组

数组适用于以下场景:

  1. 根据元素序号快速访问数据
  2. 没有频繁的插入删除操作
  3. 数组元素数量相对固定,不会频繁变化扩容

但同时,由于数组是最简单,最基础的数据结构,在需要存储一批数据数据时,如果没有其他明显更优的数据结构或者特殊需求,数组都是最保险的选择(之一)。

选择合适的数组实现

静态数组

在使用数组前,需要先创建变量,这时候就会发现一个问题,像java中的array,在定义变量的时候必须要指定类型和数组个数,如下:

int[] array = new int[5];

但是在数组的定义里面,对于数组元素的数量是没有限制的,那为什么在变量定义的时候要指定数量呢?

这是因为数组是需要连续保存数据的结构,这隐含了一个前提条件,那就是内存中需要有足够大的连续空间保存数据,这段地址需要被预留下来,不能插入其他变量数据,否则就会打破数组元素的连续性。所以为了预留足够的空间,就必须在变量定义的时候,指定数据类型和元素数量。

同样,在变量定义,内存分配完之后,就不能再增加元素数量,因为不能确保超出了预留地址之后的邻近连续地址还是空闲的,可能已经存储了其他数据。

像这种在变量定义的时候就已经确定元素数量的数组,就是静态数组。

也有资料说:静态数组是在编译时声明并分配内存空间的数组。
个人理解,这里的静态对应的理解是static关键字(静态变量/成员),和上文提到的是两种观念。

动态数组

那与静态数组相反,在变量定义的时候不用确定元素数量,且在变量使用过程中可以动态调整数组大小,就是动态数组。

那动态数组是如何实现的?其实非常简单:

  1. 动态数组和静态数组一样在变量定义的时候,就会指定数组大小用于内存空间分配(如果程序中没有指定的话,就会分配默认值),接下来
  2. 运行过程中,随着不断添加元素,当内存预留空间被用完时,将会创建一个新的更大内存空间的数组,并将之前数组的数据复制到新数组中,之后原来数组将不被继续使用

由此可见,动态数组和静态数组底层逻辑其实相同,只是动态数组贴心提供了自动扩容及“搬家”服务。像Java中的ArrayList,Python中的list,array都是动态数组。

具体使用如下
Java ArrayList :

//初始化时不定义数组大小
ArrayList<String> array = new ArrayList<String>();
array.add("array1");
array.add("array2");
array.add("array3");

Python list :

//初始化时不定义数组大小
list1 = [];
list1.append('array1')
list1.append('array2')
list1.append('array3')

可以看出,动态数组可以实现动态扩容,并且在声明时可以不定义数组大小。

静态数组 VS 动态数组

动态数组可以动态调整数组大小,在不同的语言实现中,还会封装更多的方法,使用更灵活,几乎可以胜任任何使用数组的场景,这从业务代码开发中大量的ArrayList就可以看出。

但静态数组也有其优势,动态数组为了实现动态扩容等功能,需要额外的内存存储对象头信息,导致性能不如静态数组。所以当数组大小可以明确,并且对性能有高要求时(如网络框架,图像处理等),应该使用静态数组。

数组的使用

注意数组的大小

针对静态数组,需要在定义时确定好数组大小,这时需要尽量精确,如果定义小了,那后续程序不够用到处报错,如果定义太大,又会导致内存浪费。

动态数组虽然可以动态扩容,但是这仍然是需要消耗大量性能(O(n)),所以应该尽量减少扩容的次数。因此在初始化时也需要对数组大小进行预估,并定义合适的大小,以免频繁扩容造成性能浪费。比如,要插入10000条数据,可以在创建时指定初始化大小为10000,避免大量的扩容复制迁移操作。
Java:

//初始化时定义数组大小,避免频繁扩容
ArrayList<String> array2 = new ArrayList<String>(10000);

Python:

//初始化时不定义数组大小
list2 = [None] * 10000;

注意数组中元素的类型

如上一篇文章提到的,数组其实并不一定要求元素类型一致(只要求大小),但是出于实际业务场景和开发的需要,一般还是会指定相同的数据类型。

同时在一些高级语言中,如Java,使用ArrayList时无法使用基本类型,只能用Integer,Long等封装类,这会产生装箱和拆箱的操作,造成性能影响,所以如果有类似场景并且对性能有影响,可以直接使用Array。

结束

数组篇基本就到此为止,下一篇将开始链表。数组相关的使用写的比较少,因为确实简单。等后面写到更多数据结构,体现出不同的时候就会有对比了。

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值