背景

早在linux操作系统诞生开始,c语言作为linux系统的编程语言主力,它为后续的其他高级编程语言(如c++、java)提供了很多语言级的语义和协议规范。




python既不等于也不等于 python不等于0怎么输_python既不等于也不等于


数组做为linux操作系统最基本的数据结构之一,便是其中的一项语言级高级特性,深入理解数组有助于大家更深入的了解计算机系统原理。

寻址:从0开始

首先,我们了解下数组的基本特性

1、线性表结构

2、一组连续的内存空间

3、存储相同类型数据

由数组的基本特性可知:数组所申请的内存是一段连续的内存地址,其存储的是相同类型的值。


python既不等于也不等于 python不等于0怎么输_python既不等于也不等于_02


从其数组内存模型定义来看,数组的访问是从首地址(偏移量为0)开始,如果想访问下一个数组元素,需要把位置偏移,也就是数组内存寻址时,需要把偏移量变为1,以此类推。

计算数组内存寻址公式:

array[i] = base_address + i * data_type_size

参数说明

  1. base_address 首地址array[0] ,数组第一个元素内存地址
  2. i 为偏移量
  3. data_type_size 数据类型字节大小

举个例子:

1、定义一个int 数据类型的数组,a为变量,数组长度为5

int[] a=new int[5]

2、假设数组地址:

  1. 第一个内存地址为:1008
  2. 第二个为:1009
  3. 第三个为:1010
  4. ...


python既不等于也不等于 python不等于0怎么输_数据_03


3、寻址:由公式:array[i] = base_address + i * data_type_size


python既不等于也不等于 python不等于0怎么输_数组_04


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“就多了一次减法指令。


python既不等于也不等于 python不等于0怎么输_数据_05


历史原因

c语言的设计者使用了0开始编号,后续的很多高级编程语言也就沿用了这个规范,降低额外的学习和理解成本。

关心话题(二):随机访问

由于数组是线性结构,那么根据首地址和偏移量就可以计算出任意数组元素的内存地址

array[i] = base_address + i * data_type_size

java面试题:数组和链表的区别

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

2、数组适合查找,查找的时间复杂度为O(1)


python既不等于也不等于 python不等于0怎么输_python既不等于也不等于_06


究其原因是数组支持随机访问,根据下标随机访问的时间复杂度是O(1),而链表需要从头开始寻址,直到找到对应的元素地址才结束,其复杂度为O(logn)

关心话题(三):集合能替代数组吗?


python既不等于也不等于 python不等于0怎么输_python既不等于也不等于_07


数组和集合最大一个区别于在于数组能直接存储基本的数据类型(如int、float、long等);而集合只能通过装箱和拆箱存储基本数据类型,代价是需要消耗性能。另外使用多维数组时,用数组会直观一些。

jvm标记清除算法


python既不等于也不等于 python不等于0怎么输_数组_08


为了避免数组大规模的数据搬移,可以将k位置的数据直接搬移到数组末尾位置,再把新数据放到k位置。删除时,可以将要删除的数据标记下来,当数组没有足够的空间时,将标记的数据统一删除,就可以提高很大的性能,也就是jvm标记清除垃圾回收的思想 。

总结

大部分高级程序语言的数组下标是从0开始的,而python数组下标却可以支持负数 。