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

您所在的位置:网站首页 数组为什么要从0开始 为什么很多编程语言中数组都是从 0 开始编号

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

2024-07-16 18:03| 来源: 网络整理| 查看: 265

正文 1 为什么很多编程语言中数组都是从 0 开始编号 1.1 效率原因

从内存模型来看,“下标”也称为“偏移”。

我们知道在C语言中数组名代表首地址(第一个元素的地址),a[0]就是偏移为 0 的位置。a[k]就表示偏移 k 个元素类型大小的位置。得出计算公式:

a[k]_address = base_address + k * type_size

但是钥匙从 1 开始计数,那这个公式就会变为:

a[k]_address = base_address + (k-1) * type_size

对比两个公式,如果从 1 开始编号,每次随机访问数组元素就多了一次减法运算,对于CPU来说就是多了一次减法指令。

数组作为非常基础的数据结构,通过下标访问数组元素又是数组上的基础操作,效率优化应做的很好,所以为了减少一次减法操作,数组选择了从 0 开始编号。

1.2 历史原因

C语言的设计者用 0 开始计数下标,之后的Java、C++等高级语言都效仿C语言,沿用了从0开始计数的习惯。

还有一些语言并不是从0开始计数的,如:Matlab。

据我所知:python还支持负数下标。

2 数组的特点 2.1 随机访问

数组是一种线性数据结构,占用一段连续的内存,存储相同类型的数据。

例如:这样一段代码

int arr[10] = { 0 }; for (int i=0; i(40)10

数组随机访问时:通过计算元素存储位置的内存地址来访问相应的元素

a[i]_address = base_address + i * data_type_size

数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。

2.2 低效的“插入”和“删除” 2.2.1 低效原因

数组为了保持内存数据的连续性,会导致插入、删除这两个操作比较低效。

插入:

假设数组长度为n,要将一个数据插入到第 k 个位置,为了把第 k 个位置腾出来,我们需要将k~n这部分元素顺序的向后移动一位。

插入的时间复杂度:

最好情况:在数组的末尾插入元素,不需要移动数据了,时间复杂度为O(1)。

最坏情况:在开头插入元素,那就需要把所有的数据向后移动一位,时间复杂度为O(n)。

平均时间复杂度:(1+2+…+n)/n = O(n)。

删除:

删除操作和插入操作类似,删除了某一元素后,需要搬移数据。

和插入类似,如果删除数组末尾的数据,则最好情况时间复杂度为O(1),如果要删除开头数据,则最坏情况时间复杂度为O(n),平均时间复杂度为O(n)。

2.2.2 改进方法

插入:

如果数组中的元素没有任何规律,数组只是被当作一个数据集合,在这种情况下,如果要将某个数据插入到第k个位置,为了避免大规模的数据迁移,一个简单的办法就是直接将现在第k个元素放到最后,把新元素放进来。*

例如:arr[10] = {a,b,c,d,e}要将x插入第三个位置arr[10]={a,b,x,d,e,c}

这样插入的时间复杂度为O(1),这种方法在快速排序中也会用到。

删除:

在某些特殊情况下,我们并不一定非得追求数组中数据的连续性,如果我们将多次删除操作放在一起执行,效率会高很多。*

举个例子:a[10]={a,b,c,d,e,f,g,h} 如果我们要依次删除abc三个元素,需要搬移三次后面的数据,为了避免这个重复的搬移工作,可以先记录下来已经删除的数据,每次的删除操作并不是真正的搬移数据,只是记录数据已经被删除,当数组中没有更多的空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了搬移工作,这也是标记清除垃圾回收算法的核心思想。

3 数组越界问题

有如下代码:

int main(int argc, char* argv[]){ int i = 0; int arr[3] = {0}; for(; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3