数组:为什么很多编程语言中数组都从0开始编号
如何实现随机访问
什么是数组?数组array是一种线性表数据结构,用一组连续的内存空间,来存储一组具有相同类型的数据
①线性表:数据排成像一条线一样的结果,每个线性表上的数据只有前或后两个方向。数组、链表、队列、栈也是线性表结构
非线性表有二叉树、堆、图等,数据之间并不是简单的前后关系
②连续的内存空间和相同类型的数据
可以进行随机访问,但为了保证连续性,需要做大量的数据搬移工作
数组实现下标随机访问数组元素:长度为10的int类型的数组int[] a = new int[10]举例,给a[10]分配了一块连续内存空间1000~1039,计算机会给每个内存单元分配一个地址,可以通过地址来访问内存中的数据,当计算机需要随机访问数组中的某个元素时,首先通过寻址公式a[i]_address = base_address + i * dat,计算出该元素存储的内存地址.
数组和链表的不同:
数组是适合查找操作,但是查找的时间复杂度并不为O(1),即便是排好序的数组,用二分查找时间复杂度也是O(logn),正确的表述是:数组支持随机访问,根据下标随机访问的时间复杂度为O(1),链表适合插入、删除,时间复杂度为O(1)
低效的插入和删除
插入操作:如果是在数组的末尾插入元素,就不需要移动数据,时间复杂度为O(1),但如果在开头插入元素,需要所有的数据都往后移动一位,所以最坏复杂度为O(n),平均情况复杂度为O(n).
假设数组a[10]中存储了如下5个元素:a,b,c,d,e,我们需要将元素x插入到第3个位置,我们只需要将c放入到a[5],将a[2]赋值为x即可,这样时间复杂度就会降为O(1)
删除操作:要删除第k个位置的数据,可以将多次删除操作集中在一起执行
数组a[10]存储了8个元素,a,b,c,d,e,f,g,h,要依次删除a,b,c三个元素,为了避免d,e,f,g,h几个数据被搬移3次,先记录下已经删除了的数据,每次删除操作并不是真正的搬移数据,只是记录数据已经被删除,当数组没有更多空间存储数据时,再触发执行删除操作导致的数据搬移
这就是JVM标记清楚垃圾回收算法的核心思想
数组的访问越界问题
int main(int argc,char * argv[]{
int i = 0 ;
int arr[3] = {0};
for(;i <= 3 ;i++){
arr[i] = 0;
printf("hello world\n");
}
return 0 ;
})
这段代码会打印无限行"hello wolrd",因为数组大小为3,a[0],a[1],a[2],所以当i = 3的时候,数组a[3]访问越界
在c语言中,只要不是访问受限的内存,所有内存空间都是可以自由访问的,a[3]会被定位到某块不属于数组的内存地址上,而这个地址正好是存储变量I 的内存地址,那么a[3] = 0 ,相当于 i = 0 ,会导致代码无限循环
数组越界在C语言是一种未决行为,并没有规定数组访问越界时编译器应该如何处理,因为访问数组的本质就是访问一段连续内存,只要数组通过偏移计算得到的内存地址是可用的,程序就不会报错
函数体内的局部变量存在栈上,且连续压栈,在linux进程的内存布局中,栈区在高地址空间,从高到低增长,i占4字节,接着arr占12字节,内存从高到低:地址依次是:i,a[2],a[1],a[0],a[3]通过寻址公式,计算得到的正好是i 的存储地址,所以a[3]=0,相当于i = 0 .变量i和arr在相邻地址,且i比arr的地址大,所以arr越界正好访问到i
c语言关于数组的内存分配说明?????????
容器能否完全替代数组
针对数组类型,很多语言都提供了容器
什么时候用数组更合适点:
①Java ArrayList无法存储基本类型,比如Int、long,需要封装为Integer、Long类,如果特别关注性能,或希望使用基本类型,可以选用数组
②若数据大小事先知道,并且对数据的操作非常简单,直接使用数组
对于业务开发,直接使用容器足够,如果做非常底层的开发,性能的优化需要做到极致,使用数组
为什么大多数编程语言,数组从0开始编号,而不是从1开始?
从数组存储的内存模型上看,下标最确切的定义应该是偏移offset,用a来表示数组的首地址,a[0]是偏移为0的位置,就是首地址,a[k]表示偏移k个type_size的位置,所以计算a[k]的内存地址需要a[k]_address = base_address + k * type_size,但是如果从1开始计数,计算数组元素a[k]的内存地址为:a[k]_address = base_address + (k-1)*type_size,从1开始编号,每次随机访问数组元素都多一次减法运算,对于cpu来说,多一个减法指令,所以为了效率 的优化,减少一次减法操作,数组选择从0开始编号
二维数组的内存寻址公式是?
对于m*n的数组,a[i] [j](i < m,j < n)的地址为address = base_address + (i * n + j) * type_size
按行连续存放,行序有限的存储 float a[3] [5]
a_00 a_01 a_02 a_03 a_04
a_10 a_11 a_12 a_13 a_14
a_20 a_21 a_22 a_23 a_24
a[i] [j]的首地址= p + (i * col +j)* 4