如何实现随机访问
-
什么是数组
-
线性表数据结构
- 线性表数据像一条线
- 线性表(最多只有前和后两个方向):数组,链表、队列、栈等等
- 非线性表(并不是简单的前后关系):二叉树、堆、图等
-
连续的内存空间,存储一组相同类型的数据
-
-
数组的特点
-
线性表
-
连续的内存空间和相同类型的数据 (是随机访问的前提条件,也是大量数据搬移的主要原因)
- 内存地址的访问公式:a[i]_address = base_address + i * data_type_size
-
数组在随机访问的情况下时间复杂度为O(1)
-
低效的“插入”和“删除”
-
插入操作
-
平均时间复杂度o(n)
- 第一个位置是o(1)
- 最后一个位置是o(n)
- 平均情况时间复杂度为 (1+2+...n)/n=O(n)\
-
每次都需要移动n-k个元素
-
优化手段:不需要有序的场景下直接和空数据swap即可
-
-
删除操作
- 平均时间复杂度o(n)
- 优化:懒删除 每次记录删除下标,当存储不够的时候真正执行删除操作 JVM标记清除垃圾回收算法的核心思想
警惕数组的访问越界问题
-
c语言中不会校验数据越界
-
访问数组的本质就是访问一段连续内存,只要数组通过偏移计算得到的内存地址是可用的,那么程序就可能不会报任何错误\
-
利用数组越界进行非法攻击
容器能否完全替代数组?
-
容器的优点:
- 封装数据操作细节
- 支持动态扩容,将不够用的数组复制大更大的数组中
- 可以在初始化容器时指定容器大小
-
特点
-
Java ArrayList 无法存储基本类型 Autoboxing、Unboxing 有一定的性能消耗\
-
数据大小事先已知则可用数组\
-
多维数组比多维list更直观\
-
-
业务开发使用list就够了,没必要为了一点性能而使用数组
-
当性能是第一标准时,才真正使用数组
解答开篇
-
下标”最确切的定义应该是“偏移(offset)\
-
a[k]_address = base_address + k * type_size
-
如果起始位置从1开始则是a[k]_address = base_address + (k-1)*type_size 需要多执行一次减法指令
总结
-
数组
- 用一块连续的内存空间,来存储相同类型的一组数据
- 随机访问o(1)
- 追求极致性能可以用数组
\