我们在用数组的时候,直接定义一个数组,根据下标删除,或者根据下标增加,又或者遍历,这些都是最基本的操作,但是呢?你有没有考虑过数组是怎么实现的,以及怎样使用数组效率最高,还有数组下标为什么从0开始呢?这便是我们探讨的问题:
数组是什么?
如果学过数据结构(这个对了解底层非常重要!),就知道,他是一个线性表数据结构,与之,链表,队列,栈也是。还有一种数据结构为非线性表,例如图,堆,二叉树。区别就在于线性表中,有前后关系:
原谅我用下墨刀画图
数组占了多少内存?
我们定义一个长度为10的int类型的数组int[] a = newint[10]来举一个热腾腾的栗子,分配了一块连续内存空间1000~1039,因为int,是最基本的类型,默认是4个字节,一般和CPU的字宽一致,为了提高CPU的处理速度。
其中,计算机会给每个内存单元分配一个地址,计算机可以通过地址来访问内存中的数据。当计
算机需要访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内
存地址,内存块的首地址为base_address = 1000,
a[i]_address = base_address + i * data_type_size//内存寻址公式,寻址公式有7种
数据类型,字节大小表
如上,我们定义了10个int类型的变量,所以是40字节,内存占用1000~1039正确。不同的数据类型占用不同的内存。
插入和删除,怎样避免消耗性能?
我们定义一个数组(用的JS写法):
var arr=[1,2,3,4,5];
往数组末尾添加元素,发现并没什么性能上的问题。
arr.push(6);
但是往数组中间放元素就不一样了:
arr.splice(2,0,5);//在下标2处,添加一个5元素,最后输出为[1,2,5,3,4,5];
为什么会不一样呢?就是因为性能的元素,往中间插入元素,后面的元素,会往后移一位,这对性能消耗是非常大的,如果在最后插入元素,那么不用挪位,时间复杂度为O(1),如果在最前面,时间复杂度为O(n),那么平均复杂度则为O(n)。
有没有什么方法可以不那么消耗性能?当然是有,我们可以把要添加的元素位置,进行替换,然后再把被替换的,放到数组最后面去,这样也可以完成操作,在快速排序算法中,就是用的这种思想。
arr.push(arr[3]);
arr[3]=5;
这样就完成啦。至于删除,大同小异,不过删除这操作,为了避免数组的元素挪动,以及多次删除,可以将多次删除,整合到一起删,这样效率就会提高了。还有一种是我想出来的方法,把要删除的元素,设置成undefined(JS),然后通过for in循环,就可以删除undefined的数据啦。
PS:Java底层虚拟机JVM标记清除垃圾回收算法的核心思想也是这个,数据结构是底层的东西,学好了这个,学其他高级语言,都非常容易。
数组为什么是从0开始:
首先,定义就是这样子定义的,1+1=2,人就是这样定义,这些东西是证明不了的,arr[0]这里的0是指的偏移量。
a[i]_address = base_address + i * data_type_size
套用上面的寻址公式,就这么简单。(当然,有些例外,Python下标可以从负数开始,MatLab下标不是从0计数等等)
网友评论