2. 数组:为什么很多编程语⾔中数组都从0开始编号

数组是一种线性表数据结构,其随机访问特性使其在特定场景下优于链表。数组通过偏移量进行访问,下标0表示首地址。虽然插入和删除操作效率低,但根据下标访问的时间复杂度为O(1)。ArrayList作为高级封装,提供了动态扩容等便利,但在性能和存储基本类型方面,有时数组更具优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数组(Array) 是⼀种线性表数据结构。 它⽤⼀组连续的内存空间, 来存储⼀组具有相同类型的数据。
线性表(Linear List):线性表就是数据排成像⼀条线⼀样的结构。 每个线性表上的数据最多只有前和后两个⽅向。 其实除了数组, 链表、 队列、 栈等也是线性表结构。
⾮线性表, ⽐如⼆叉树、 堆、 图等。 之所以叫⾮线性, 是因为, 在⾮线性表中, 数据之间并不是简单的前后关系。
连续的内存空间和相同类型的数据。 正是因为这两个限制, 它才有了⼀个堪称“杀⼿锏”的特性: “随机访问”。 但有利就有弊, 这两个限制也让数组的很多操作变得⾮常低效, ⽐如要想在数组中删除、 插⼊⼀个数据, 为了保证连续性, 就需要做⼤量的数据搬移⼯作。

我们知道, 计算机会给每个内存单元分配⼀个地址, 计算机通过地址来访问内存中的数据。 当计算机需要随机访问数组中的某个元素时, 它会⾸先通过下⾯的寻址公式, 计算出该元素存储的内存地址:


其中data_type_size表示数组中每个元素的⼤⼩。 我们举的这个例⼦⾥, 数组中存储的是int类型数据, 所以data_type_size为4个字节。从数组存储的内存模型上来看, “下标”最确切的定义应该是“偏移(offset) ”。 前⾯也讲到, 如果⽤a来表示数组的⾸地址, a[0]就是偏移为0的位置, 也就是⾸地址, a[k]就表示偏移k个type_size的位置。

数组和链表的区别, 很多⼈都回答说, “链表适合插⼊、 删除,时间复杂度O(1); 数组适合查找, 查找时间复杂度为O(1)”。实际上, 这种表述是不准确的。 数组是适合查找操作, 但是查找的时间复杂度并不为O(1)。 即便是排好序的数组, 你⽤⼆分找, 时间复杂度也是O(logn)。 所以, 正确的表述应该是, 数组⽀持随机访问, 根据下标随机访问的时间复杂度为O(1)。

ArrayList相当于C++ 的vector,用于存储对象。

ArrayList的优势:

  • 将很多数组操作的细节封装起来。 ⽐如前⾯提到的数组插⼊、 删除数据时需要搬移其他数据等。
  • ⽀持动态扩容。
  • arraylist里可以同时存放不同类型的对象(自己加的)

数组本身在定义的时候需要预先指定⼤⼩, 因为需要分配连续的内存空间。 如果我们申请了⼤⼩为10的数组, 当第11个数据需要存储到数组中时, 我们就需要重新分配⼀块更⼤的空间, 将原来的数据复制过去, 然后再将新的数据插⼊。
如果使⽤ArrayList, 我们就完全不需要关⼼底层的扩容逻辑, ArrayList已经帮我们实现好了。 每次存储空间不够的时候, 它都会将空间⾃动扩容为1.5倍⼤⼩。
不过, 这⾥需要注意⼀点, 因为扩容操作涉及内存申请和数据搬移, 是⽐较耗时的。 所以, 如果事先能确定需要存储的数据⼤⼩, 最好在创建ArrayList的时候事先指定数据⼤⼩。作为⾼级语⾔编程者, 是不是数组就⽆⽤武之地了呢? 当然不是, 有些时候, ⽤数组会更合适些, 我总结了⼏点⾃⼰的经验。

ArrayList的劣势:
1.Java ArrayList⽆法存储基本类型, ⽐如int、 long, 需要封装为Integer、 Long类, ⽽Autoboxing、 Unboxing则有⼀定的性能消耗, 所以如果特别关注性能, 或者希望使⽤基本类型, 就可以选⽤数组。
2.如果数据⼤⼩事先已知, 并且对数据的操作⾮常简单, ⽤不到ArrayList提供的⼤部分⽅法, 也可以直接使⽤数组。
3.还有⼀个是我个⼈的喜好, 当要表示多维数组时, ⽤数组往往会更加直观。 ⽐如Object[][] array; ⽽⽤容器的话则需要这样定义: ArrayList<ArrayList > array。
 对于业务开发, 直接使⽤容器就⾜够了, 省时省⼒。 毕竟损耗⼀丢丢性能, 完全不会影响到系统整体的性能。 但如果你是做⼀些⾮常底层的开发, ⽐如开发⽹络框架, 性能的优化需要做到极致, 这个时候数组就会优于容器, 成为⾸选。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值