数据结构与算法之美【总结笔记】 -- 数组

数组是一种线性的数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。

数组中存储的数据,地址是连续的,所以支持随机性访问时间复杂度为O(1);

由于需要保持地址的连续性,所以在对数组进行插入和删除的时候,需要对目标数据之后的所有数据进行地址移动的操作,此操作的时间复杂度,最好是O(1),最坏是O(n),平均是O(n)。

针对此问题可采取的解决办法举例:

插入操作:如果此数组只是用来存储一组数据,对于其数据的顺序严格要求,则可采取以下操作,如果要将某个数据插入到K的位置,则将K位置上的数据转移到数组最后,然后将K位置的数据替换为目标数据,此操作时间复杂度为O(1)

数据结构与算法之美【总结笔记】 -- 数组

删除操作:将要删除的数据先只做一个标记,然后等到数组没有空闲空间的时候,在一次性将标记的数据删除,这样虽然不会改变删除操作的时间复杂度,但是会大大降低操作的执行次数,提升性能。

容器与数组

容器具有极强的可用性,因为java的开发者已经将数组的各种操作进行了封装(例如List、Set),使用者不需要考虑内存的扩容申请,指针是否越界等问题,并且有大量的封装好的方法来操作数据,在进行业务开发的时候可以选用容器,降低一点点能行来换取高效的功能开发是可以接受的。而当我们是基于底层的开发时,例如网络框架,性能是我们的首选,性能优化需要做到极致,这个时候就不要选择容器,而是选择直接操作数组。

小提示:ArrayList会在数组空间不够是自动扩容为当前容量的1.5倍,因为扩容涉及到新数组内存的申请,原始数据的转移等一系列操作,所有会消耗大量性能,所有当我们预先知道需存储的数据量的时候,可以预先在ArrayList的构造函数中传入数组大小,避免没必要的扩容操作。

数组下标为何以0开始,原因有二,数组中第一个数据的地址作为数组的地址,对数组执行随机访问的时候,传入的地址K会执行下列公式计算目标地址,如果以1开始的话,则需要多进行一个k-1的操作,这样可以看成是对性能的一个极致优化的例子。第二个原因是,最开是C语言就是以0开始,其他后来的语言例如java做了借鉴,方便老一批程序员的学习使用。

a[k]_address = base_address + k * type_size