数组
基本概念
一维数组
数组(Array)是计算机科学中的基础数据结构,具有以下特性和定义:
- 固定大小: 数组在创建时具有固定的大小。
- 连续的内存存储: 数组中的所有元素都存储在连续的内存地址中。
- 同一类型的元素: 数组只能存储一种类型的元素,例如:整数数组只能存储整数。这表示数组中每个元素占用内存的大小都一样。
- 索引的时间复杂度是常数: 基于上两条特性,我们可以通过简单的数学计算来直接访问数组中的任何元素:
元素在内存中的地址 = 数组的起始 内存地址 + 索引 * 单个元素占用的内存
访问数组中元素,也就是索引的时间复杂度是 。 - 插入与删除的时间复杂度为线性: 在数组的中间插入或删除元素通常需要移动其他元素,因此这类操作的时间复杂度是 ,其中 n 是数组的大小。
- 缓存友好性: 由于数组的连续内存布局,它们通常比其他非连续的数据结构更能利用 CPU 缓存,这可以加速访问速度。
多维数组
多维数组,通常称为矩阵或张量,是一个数组,其中每个元素本身都是一个数组。最常见的多维数组是二维数组 ,但理论上可以有任意数量的维度。每个维度通常被称为一个“轴”。
二维数组是最常见的多维数组形式,通常用于表示矩阵。在二维数组中,每个元素都是一个数组。例如,一个数字表格可以被表示为一个二维数组。二维数组在内存中存储顺序是先放置一行的数据,然后紧接着保存下一行。因为每一行的元素的个数都相同,所以通过元素的索引还是可以立刻计算到元素所在的内存地址。比如一个二维数组,共有 n 行 m 列,需要访问的元素的索引是第 i 行 j 列,那么就可以知道这个 元素的内存地址 = 数组的起始内存地址 + (m * i + j) * 单个元素占用的内存
。
在三维数组中,每个元素都是一个二维数组。以此类推,可以构建更高维数组。
计算机里存储的图片时最常见的数组格式的数据。黑白图片通常是一个二维数组,其中每个元素代表一个图片像素。彩色图像则通常是一个三维数组,两个维度代表像素的位置,第三个维度代表红、绿和蓝三种颜色。
Python 中的数组
在 Python 中,列表(list)是一个动态数组,而不是最基本的数组结构。它在内存中使用一个连续的内存块来存储元素,因此可以快速地随机访问任何元素。区别是列表可以动态调整大小:当我们向 list 添加元素并超出其当前容量时,Python 会分配一个新的、更大的内存块来存储元素,并将旧块中的元素复制到新块中。这是为什么 list 被称为动态数组的原因。由于使用连续内存,向 list 的中间位置插入或从中间位置删除元素需要移动后面的元素,这是一个 的操作。但在 list 的末尾添加或删除元素通常是更快的,因为不需要挪动其它元素。
与真正的数组相比,Python 的 list 有一些额外的内存开销,因为它可能预先分配一些额外的空间来加速后续的元素添加。
至于列表的列表,比如 [[1, 2, 3], [4, 5]]
就更不是真正的多维数组了。
在 Python 中需要使用数组进行数学计算的时候,一般会使用 NumPy(Numerical Python的简写) 中的 array。与 list 相比 np.array 中的所有元素都是相同的数据类型,例如整数、浮点数或字符串。np.array 可以是多维的。例如,它可以代表向量(1D)、矩阵(2D)或更高维的张量。我们会在专门一节详细介绍 NumPy。在这里,为了简化程序,仍然使用列表演示数组的各种算法。
常用的数组操作
查找数组中的最大值
这个算法非常直接,首先将数组的第一个元素设置为当前的最大值,然后遍历数组,每次找到一个比当前最大值更大的值时,就更新最大值。最后,函数返回找到的最大值。这种方法的时间复杂度是 O(n),其中 n 是数组的长度。
def find_max_value(arr):
"""查找数组中的最大值"""
# 检查输入数组是否为空
if not len(arr):
return none
# 设置当前结果为元素第一个值
max_value = arr[0]
# 遍历数组
for num in arr:
if num > max_value:
# 如果有更大值,就更新当前结果
max_value = num
return max_value
在面试中遇到的类似题目会稍微增加一点难度,比如找第二大的,第三小的数等。但算法还是一样的,找第二大的数,无非就是再增加一个变量,使用两个临时变量分别记录当前最大的和第二大的数。