03 数组:为什么很多编程语言中数组都从0开始编号?

03 数组:为什么很多编程语言中数组都从0开始编号?

一、为什么很多编程语言的数组都是从0开始编号的?

  1. 从数组存储的内存模型上来看,“下标” 确切的说法就是一种”偏移”,相比从1开始编号,从0开始编号会少-次减法运算, 数组作为非常基础的数组结构,通过下标随机访问元素又是非常基础的操作,效率的优化就要尽可能的做到极致。
  2. 主要的原因是历史原因,C语言的设计者是从0开始计数数组下标的,之后的Java、JS等语言都进行了效仿,或者说是为了减少从C转向Java、JS等的学习成本。

二、什么是数组?

  • 数组是一个线性数据结构,用一组连续的内存空间存储一组具有相同类型的数据。
  • 其实数组、链表、栈、队列都是线性表结构;树、图则是非线性表结构。

三、数组和链表的面试纠错

  1. 数组中的元素存在一个连续的内存空间中, 而链表中的元素可以不存在于连续的内存空间。
  2. 数组支持随机访问,根据下标随机访问的时间复杂度是0(1);链表适合插入、删除操作,时间复杂
    度为O(1)。

四、容器是否完全替代数组?

容器的优势:对于Java语言,容器封装了数组插入、删除等操作的细节,并且支持动态扩容。对于Java,一些更适合用数组的场景:

  1. Java的ArrayList无法存储基本类型, 需要进行装箱操作,而装箱与拆箱操作都会有一定的性能消
    耗,如果特别注意性能,或者希望使用基本类型,就可以选用数组。
  2. 若数组大小事先已知,并且对数组只有非常简单的操作,不需要使用到ArrayList提供的大部分方
    法,则可以直接使用数组。
  3. 多维数组时,使用数组会更加直观。

五、JVM标记清除算法

GC最基础的收集算法就是标记-清除算法,如同他们的名字一样, 此算法分为“标记”、“清除” 两个
阶段,先标记出需要回收的对象,再统- -回收标记的对象。不足有二,一是效率不高, 二是产生碎片内
存空间。

大多数主流虚拟机采用可达性分析算法来判断对象是否存活,在标记阶段,会遍历所有 GC ROOTS,将所有 GC ROOTS 可达的对象标记为存活。只有当标记工作完成后,清理工作才会开始。

不足:

  • 效率问题。标记和清理效率都不高,但是当知道只有少量垃圾产生时会很高效。
  • 空间问题。会产生不连续的内存空间碎片。
  • 另外,对于数组访问越界造成无限循环,我理解是编译器的问题,对于不同的编译器,在内存分配时,会按照内存地址递增或递减的方式进行分配。老师的程序,如果是内存地址递减的方式,就会造成无限循环。

六、数组的内存寻址公式

一维数组:
$$
a[i]_address=base_address+i*typesize
$$

二维数组假设是,对于 $mn$ 的数组,$a[i]][j]$ (i < m,j < n)的地址为:
$$
a[i][j]_address=base_address + (i
n+j)typesize
$$
三维数组假设是,对于 $m
n*q$ 的数组

$$
a[i][j][k]_address=base_address + (inq + jq + k)typesize
$$

原文地址:https://www.cnblogs.com/yuanhang110/p/12962086.html