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

【其中S表示原文,A表示我的个人解释】

【请注意,这里面充满大量不成熟的、主观推测的看法】

【大家可以去极客时间支持各位老师的专栏,都是很不错的内容】

S1:如果数组中的数据是有序的,我们在某个位置插入一个新的元素时,就必须按照刚才的方法搬移 k 之后的数据。但是,如果数组中存储的数据并没有任何规律,数组只是被当作一个存储数据的集合。在这种情况下,如果要将某个数据插入到第 k 个位置,为了避免大规模的数据搬移,我们还有一个简单的办法就是,直接将第 k 位的数据搬移到数组元素的最后,把新的元素直接放入第 k 个位置……利用这种处理技巧,在特定场景下,在第 k 个位置插入一个元素的时间复杂度就会降为 O(1)。

A1:也就当且仅当:数组只是一个存储数据的集合,里面的元素之间没有强关联的先后关系,也就是随意和无序存放,当我们想要要将指定值插入某位置时,由于并非有强关联的先后关系,所以该位置的元素就可以随意放在其他任何位置,而复杂度最低的情况就是将该位置的元素直接插在末尾(直接赋值即可),然后再将指定值赋值给该位置的存储空间,覆盖原值,完成插入。不过,这样的场景应该是不多见的,毕竟存放一堆无序且随意的数据,虽然方便插入,但并不方便删除和查找。这种插入方法会在特定的应用场景下非常高效,尤其是当数据的有序性不是关键需求,而快速插入更为重要时。

S2:在某些特殊场景下,我们并不一定非得追求数组中数据的连续性。如果我们将多次删除操作集中在一起执行,删除的效率是不是会提高很多呢……数组 a[10]中存储了 8 个元素:a,b,c,d,e,f,g,h。现在,我们要依次删除 a,b,c 三个元素。为了避免 d,e,f,g,h 这几个数据会被搬移三次,我们可以先记录下已经删除的数据。每次的删除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。

A2:这种操作应该只适用于待删除元素之间是连续的情况(如1,2,3,4,5中的1,2,3,而1,2,5就不能适用其中了),且删除操作也是连续进行的,因为如果恰好要在某处待删除元素的位置插入一个元素,但该位置又被标记了,会在后续的一次性删除中被覆盖,从而导致数据错误。与S1中的插入场景语言,这样的场景应用应该也是不多的,应该只能用于只在数组末尾进行插入、只进行删除操作、数组元素之间有强关联(如后面的元素要被删除就必须删除前面的元素,这样才能保证删除的连续性)的场景。但如果能够有效管理“已删除”标记和确保插入操作与之兼容,此策略可以应用于更广泛的情境。

S3:在 C 语言中,只要不是访问受限的内存,所有的内存空间都是可以自由访问的……数组越界在 C 语言中是一种未决行为,并没有规定数组访问越界时编译器应该如何处理。因为,访问数组的本质就是访问一段连续内存,只要数组通过偏移计算得到的内存地址是可用的,那么程序就可能不会报任何错误……这种情况下,一般都会出现莫名其妙的逻辑错误……debug 的难度非常的大。而且,很多计算机病毒也正是利用到了代码中的数组越界可以访问非法地址的漏洞,来攻击系统,所以写代码的时候一定要警惕数组越界。

A3:我认为,这意味着在C语言这样给予程序员极高自由度的语言中,要时刻注意逻辑界限和物理界限,数组(其实应该说所有的数据结构)的边界只在逻辑上存在,而在物理上它并不存在,物理上只要能够通过寻址公式找到的位置,其内容都是可供操作的(除非语言在底层逻辑上阻止这种操作)。

S4:前面我们讲到一维数组的内存寻址公式,那你可以思考一下,类比一下,二维数组的内存寻址公式是怎样的呢?

A4:我个人认为,二维数组其本质来说,也是一维数组,因为任何维的数组反映在内存空间上都是一串连续的一维数据,二维数组与一维数组的区别在于将整块一维数组逻辑上以另一种基本单位进行了重新划分,一维的基本单位是单个内存单元,而二维数组的基本单元则是n个内存单元,而单个内存单元则成了最小的操作单元,而更高维的数组,则是换了划分细致的基本单元。所以二维数组a[m][n]的寻址公式为:a[i][j]_adress(i<m,j<n) = a[0][0]_adress + (i*n + j) * data_type_size。由于二维数组在内存地址上本质就是一个一维数组,所以,假如i*n+j=k的话,a[i][j]_adress(i<m,j<n) = a[0][0]_adress + k* data_type_size。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值