数据结构------数组

什么是数组?

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

关键字解读:

“连续的内存空间”和“相同类型”,是数组有了一个堪称“杀手锏”的特性:“随机访问”。但是这两个限制也让数组的很多操作变得非常低效,比如数组中删除,插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。

如何实现根据下标随机访问数组元素?

拿⼀个⻓度为10的int类型的数组int[] a = new int[10]来举例。在我画的这个图中,计算机给数
组a[10],分配了⼀块连续内存空间1000~1039,其中,内存块的⾸地址为base_address = 1000。

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

a[i]_address = base_address + i * data_type_size

其中data_type_size表示数组中每个元素的⼤⼩。我们举的这个例⼦⾥,数组中存储的是int类型数
据,所以data_type_size就为4个字节。

数组和链表的区别:

链表适合插入,删除,时间复杂度O(1);

数组适合根据下标随机查找,查找时间复杂度为O(1)

低效的“插⼊”和“删除”

插入操作:

假设数组的⻓度为n,现在,如果我们需要将⼀个数据插⼊到数组中的第k个位置。为了把第k个位
置腾出来,给新来的数据,我们需要将第k~n这部分的元素都顺序地往后挪⼀位。那插⼊操作的时
间复杂度是多少呢?
如果在数组的末尾插⼊元素,那就不需要移动数据了,这时的时间复杂度为O(1)。但如果在数组的
开头插⼊元素,那所有的数据都需要依次往后移动⼀位,所以最坏时间复杂度是O(n)。 因为我们在每个位置插⼊元素的概率是⼀样的,所以平均情况时间复杂度为(1+2+…n)/n=O(n)。
如果数组中的数据是有序的,我们在某个位置插⼊⼀个新的元素时,就必须按照刚才的⽅法搬移k之后的数据。但是,如果数组中存储的数据并没有任何规律,数组只是被当作⼀个存储数据的集合。
在这种情况下,如果要将某个数组插⼊到第k个位置,为了避免⼤规模的数据搬移,我们还有⼀个简单的办法就是,直接将第k位的数据搬移到数组元素的最后,把新的元素直接放⼊第k个位置。利⽤这种处理技巧,在特定场景下,在第k个位置插⼊⼀个元素的时间复杂度就会降为O(1)。

删除操作:

如果我们要删除第k个位置的数据,为了内存的连续性,也需要搬移数据,不然中间就会出现空洞,内存就不连续了。
和插⼊类似,如果删除数组末尾的数据,则最好情况时间复杂度为O(1);如果删除开头的数据,则
最坏情况时间复杂度为O(n);平均情况时间复杂度也为O(n)。

题外话:容器能否完全替代数组?

ArrayList最⼤的优势就是可以将很多数组操作的细节封装起来。⽐如前⾯提到的数组
插⼊、删除数据时需要搬移其他数据等。另外,它还有⼀个优势,就是⽀持动态扩容。
数组本身在定义的时候需要预先指定⼤⼩,因为需要分配连续的内存空间。如果我们申请了⼤⼩为
10的数组,当第11个数据需要存储到数组中时,我们就需要重新分配⼀块更⼤的空间,将原来的数
据复制过去,然后再将新的数据插⼊。
如果使⽤ArrayList,我们就完全不需要关⼼底层的扩容逻辑,ArrayList已经帮我们实现好了。每次
存储空间不够的时候,它都会将空间⾃动扩容为1.5倍⼤⼩。

不过,这⾥需要注意⼀点,因为扩容操作涉及内存申请和数据搬移,是⽐较耗时的。所以,如果事
先能确定需要存储的数据⼤⼩,最好在创建ArrayList的时候事先指定数据⼤⼩。

但是在有些时候,数组会更加合适,情况主要如下:

1.Java ArrayList⽆法存储基本类型,⽐如int、long,需要封装为Integer、Long类,⽽Autoboxing、Unboxing则有⼀定的性能消耗,所以如果特别关注性能,或者希望使⽤基本类型,就可以选⽤数组。
2.如果数据⼤⼩事先已知,并且对数据的操作⾮常简单,⽤不到ArrayList提供的⼤部分⽅法,也可
以直接使⽤数组。
3.还有⼀个是我个⼈的喜好,当要表示多维数组时,⽤数组往往会更加直观。⽐如Object[][] array;⽽⽤容器的话则需要这样定义:ArrayList<ArrayList > array。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值