背景
早在linux操作系统诞生开始,c语言作为linux系统的编程语言主力,它为后续的其他高级编程语言(如c++、java)提供了很多语言级的语义和协议规范。
![b533d2a7b397774d6cea3f76f8356fc4.png](https://i-blog.csdnimg.cn/blog_migrate/8b80830c05e0c97e53053e2bff4374ee.jpeg)
数组做为linux操作系统最基本的数据结构之一,便是其中的一项语言级高级特性,深入理解数组有助于大家更深入的了解计算机系统原理。
寻址:从0开始
首先,我们了解下数组的基本特性
1、线性表结构
2、一组连续的内存空间
3、存储相同类型数据
由数组的基本特性可知:数组所申请的内存是一段连续的内存地址,其存储的是相同类型的值。
![508d5c80fc6e4ece551ea8014b86ab83.png](https://i-blog.csdnimg.cn/blog_migrate/a56c3d350597dc4dece43de4d5a1eed7.jpeg)
从其数组内存模型定义来看,数组的访问是从首地址(偏移量为0)开始,如果想访问下一个数组元素,需要把位置偏移,也就是数组内存寻址时,需要把偏移量变为1,以此类推。
计算数组内存寻址公式:
array[i] = base_address + i * data_type_size
参数说明
- base_address 首地址array[0] ,数组第一个元素内存地址
- i 为偏移量
- data_type_size 数据类型字节大小
举个例子:
1、定义一个int 数据类型的数组,a为变量,数组长度为5
int[] a=new int[5]
2、假设数组地址:
- 第一个内存地址为:1008
- 第二个为:1009
- 第三个为:1010
- ...
![113ffab3353a564cec2f67af4ab11343.png](https://i-blog.csdnimg.cn/blog_migrate/2f5f63f964095f97e5a264370d2c8cc9.jpeg)
3、寻址:由公式:array[i] = base_address + i * data_type_size
![22cdd45856d9c0fc8fe4c577183aabc5.png](https://i-blog.csdnimg.cn/blog_migrate/e2f50b54c7b913214130f43fac216429.jpeg)
a[0]——把a拿到的内存地址:
1008 + 0 = 1008 (指向第一个内存地址)
a[1]——把a拿到的内存地址:
1008 + 1 = 1009 (指向第二个内存地址)
a[2]——把a拿到的内存地址:
1008 + 2 = 1010 (指向第三个内存地址)
以此类推。。。
关心话题(一):数组下标为什么不从1开始
cpu消耗
如果数组从1开始编号,公式为a[i] = base_address + (i -1) * data_type_size,对cpu而言,”i -1“就多了一次减法指令。
![f931c05afad6b6ba379ea339ac1f50f2.png](https://i-blog.csdnimg.cn/blog_migrate/8bf6a2599b72b3e6ac1c5cac123a0609.jpeg)
历史原因
c语言的设计者使用了0开始编号,后续的很多高级编程语言也就沿用了这个规范,降低额外的学习和理解成本。
关心话题(二):随机访问
由于数组是线性结构,那么根据首地址和偏移量就可以计算出任意数组元素的内存地址
array[i] = base_address + i * data_type_size
java面试题:数组和链表的区别
1、链表适合插入和删除,时间复杂度是O(1)
2、数组适合查找,查找的时间复杂度为O(1)
![0bc3411d704a6d5af9fa8f5c18c7f43f.png](https://i-blog.csdnimg.cn/blog_migrate/a292d99f6308092e444d4c7981a1d1ca.jpeg)
究其原因是数组支持随机访问,根据下标随机访问的时间复杂度是O(1),而链表需要从头开始寻址,直到找到对应的元素地址才结束,其复杂度为O(logn) 。
关心话题(三):集合能替代数组吗?
![13005c381826dbd89381b53f1b17f78f.png](https://i-blog.csdnimg.cn/blog_migrate/731d39e387a45f1949f232ff67d9e9ae.jpeg)
数组和集合最大一个区别于在于数组能直接存储基本的数据类型(如int、float、long等);而集合只能通过装箱和拆箱存储基本数据类型,代价是需要消耗性能。另外使用多维数组时,用数组会直观一些。
jvm标记清除算法
![117f51095a308626f05c26b0b2d1c7ec.png](https://i-blog.csdnimg.cn/blog_migrate/420e14c722e2a78eebc64e1b5e7db7ef.jpeg)
为了避免数组大规模的数据搬移,可以将k位置的数据直接搬移到数组末尾位置,再把新数据放到k位置。删除时,可以将要删除的数据标记下来,当数组没有足够的空间时,将标记的数据统一删除,就可以提高很大的性能,也就是jvm标记清除垃圾回收的思想 。
总结
大部分高级程序语言的数组下标是从0开始的,而python数组下标却可以支持负数 。
最后
如果觉得本文对您有帮助的话,记得关注、转发哦,我会为大家持续提供原创干货。需要资料,请关注、转发,私信“资料”面试+微服务+springboot资料免费赠送。