数组
定义:数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据(不同语言对数组的定义标准不同,大多数语言要求同类型,而在JavaScript中,数组中元素可以是不同类型)。
解释:
1. 线性表
顾名思义,就是数据排成一条线一样的结构。每个线性表上的数据最多有前后两个方向。除了数组之外,链表、队列、栈等也是线性结构。与之对应的就是非线性表:数据之间不是简单的前后关系。
复制代码
2. 连续的内存空间和相同类型的数据
数组内的元素所占用的内存空间相同且连续,正因为这两点限制,数组才有了——随机访问——的特性。我们知道计算机会给每个内存单元(1B)分配一个内存地址,通过地址来访问。当计算机要随机访问数组中的某个元素时,首先得找出该元素的内存地址,通过下面的寻址公式来计算:a[i]_address = base_address + i * data_type_size
要注意的点:数组适合查找,查找的时间复杂度为O(1)。是不准确的。正确的说法:数组支持随机访问,根据下标的随机访问时间复杂度是O(1),仅需执行寻址一行寻址公式就可找到。
复制代码
低效的插入删除
插入:
为保证数组数据的连续性,在第k个位置上插入数据,如要保证数组元素顺序不变,则k~n这部分数据都需要往后移一位,此时k=n-1,最好的时间复杂度O(1),k=0,最坏的时间复杂度O(n)。每个位置插入的概率是一样的1/n,所以平均时间复杂度(1+2+...+n)/n = O(n)。 如果不需要保证顺序:
此时O(1)。删除:
同理插入每删除一次,保证顺序不变,则平均时间复杂度O(n)。如果在某些场景中,不一定要保证数组中数据的连续性。则可以将多次删除操作集中一次执行。每次要删除的数据都进行标记,当数组没有更多空间存储数据时,触发一次真正的删除操作。
警惕数组的访问越界问题:
这段C语言代码:C中只要不访问受限内存,所有内存空间都可以自由访问。
这段代码可能由于编译器的不同,造成结果也是不同的。1. 无限循环:根据数组的寻址公式可以知道数组a[0]~a[n-1]地址是越来越大的,栈中是从高地址向低地址增长的,因此内存排布应该是i,a[2],a[1],a[0]。访问a[3]也就等于i(前提都是相同类型数据)。2.打印4次(xcode):编译器开启堆栈保护(防止溢出漏洞如下图,通过溢出修改内存中其他区域) 开启保护后,可能会改变函数栈中变量的内存分配:数组在其他变量之前,先分配 这样数组越界就不会覆盖其他变量了。除了堆栈保护会影响结果外,CPU的字节对其也会影响结果。 C语言需要开发者注意数组越界问题,其他语言如OC,运行时会报错。数组下标为什么从0开始
解释:
- 下标确切定义应该是‘偏移量’,a[1]:偏移了一个位置。这样寻址公式:a[k]_address = base_address + k * type_size 如果从1开始:a[k]_address = base_address + (k-1)*type_size多了一步计算k-1。
- 历史原因,最开始就设计从0开始,后边的语言就一直沿用了。