数组的定义
- 线性
- 内存连续
数组是一个线性的以及内存连续的数据结构. 就是数组有前后顺序, 而且是一个挨着一个. 就跟买奶茶排队一样, 挨个排好.
线性结构
具有线性的结构:
- 数组
- 队列
- 链表
- 栈
可以就是有前后顺序, 先来后到, 从前一个可以找到后一个.
非线性结构
- 树形
- 图
非线性结构就是没有前后之分, 是比较复杂的结构.
内存连续
内存连续就是指, 存放的地方都是挨着的.
比方说:
const arr: number[] = [1, 2, 3, 4, 5]
在内存中表示:
给内存分配1000-1021的区域, 用来存放数组arr. 他们需要连续挨着.
那么我们怎么去访问数组中的数据的呢?
随机访问
就是以下公式去访问
a[i]_address = base_address + i * data_type_size
base_address: 就是指内存的开始. 例子中指的是: 1000
data_type_size: 指的是存储数据需要用多少内存.
i: 是数组中的第几个.
这样就能访问到内存地址中存储的数据了.
可以看到数组支持随机访问, 用下标去随机访问的时间复杂度为 O(1)
数组的劣势
数组为了保持内存数据的连续性,会导致插入、删除这两个操作比较低效。
插入
还是以排队来举例, 当我们排队的时候, 有个人要插队, 会让排在后面的人非常不爽.
可以看到当插入之后, 后面的每个人都需要往后移动一个位置. 这可是一个大动作了.
删除
删除相当于就是中间有个人排着排着, 不排了, 人走了. 后面的所有人都得向前移动一步, 也是个大动作了.
删除优化
当然了, 如果每次删除都移动数组的话, 内存开销会比较大, 影响性能, 咱们可以将多次删除合并, 一起操作, 减少移动.
数组为何从0开始?
对比一下从0开始, 和从1开始公式的不同
从0开始:
a[k]_address = base_address + k * type_size
从1开始:
a[k]_address = base_address + (k-1)*type_size
从1开始会多一次-1的cpu指令, 性能会差一点.