数组 (Array)

数组 (Array)

概念:连续内存空间存储相同类型元素的集合

想象一下,你有一排整齐的柜子,每个柜子的大小都一样,并且都用来存放同一种类型的物品,比如书。 数组 (Array) 就像这样一排连续的柜子,它们在计算机的内存中占据着一块连续的空间,并且只能存放相同类型的数据

  • 连续内存空间: 数组中的元素在内存中是一个挨着一个排列的,中间没有空隙。 这就像柜子是紧密排列在一起的,而不是分散在房间各处。这种连续性是数组高效访问元素的基础。
  • 相同类型元素: 一个数组只能存储同一种类型的数据,例如,整型数组只能存储整数,字符串数组只能存储字符串,不能在一个整型数组里存放字符串。 这就像你的书柜可能用来存放书籍,但不能用来存放衣服或食物。

数组数据结构示意图,显示连续的内存空间和相同类型的元素

数组的原理:索引 (Index) 与内存地址

数组之所以能够快速访问元素,关键在于它的 索引 (Index)内存地址 的关系。

  1. 索引: 数组中的每个位置都有一个编号,这个编号就是索引,通常从 0 开始计数。 例如,第一个位置的索引是 0,第二个位置的索引是 1,以此类推。
  2. 内存地址: 每个内存位置都有一个唯一的地址。 当我们创建一个数组时,计算机会分配一块连续的内存空间给它,并记录下数组的起始地址。

当我们需要访问数组中某个索引位置的元素时,计算机可以根据以下公式快速计算出该元素的内存地址:

元素地址 = 数组起始地址 + 索引 * 每个元素的大小

由于内存是连续的,并且每个元素大小相同,所以通过简单的加法和乘法运算,就能直接定位到目标元素的内存地址,从而实现快速访问。 这就像你知道了书架的起始位置,以及每本书的厚度,就可以快速计算出任意一本指定位置的书在书架上的位置。

数组的声明 (Declaration):

在不同的编程语言中,声明数组的语法略有不同,但基本思想是相同的: 指定数组的类型、名称和大小(有些语言中大小是动态的)。

  • Python: (动态数组 - List)

    Python 中的 list 是一种动态数组,它更灵活,大小可以动态调整。

    1
    2
    3
    4
    5
    6
    7
    8
    # 声明一个整型列表
    integer_array = [1, 2, 3, 4, 5]

    # 声明一个字符串列表
    string_array = ["apple", "banana", "cherry"]

    # 声明一个空列表
    empty_array = []
  • Java: (静态数组 和 ArrayList)

    Java 中既有静态数组,也有动态数组 ArrayList

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 声明一个静态整型数组,大小为 5
    int[] intArray = new int[5];

    // 声明并初始化一个静态整型数组
    int[] initializedIntArray = {1, 2, 3, 4, 5};

    // 声明一个动态数组 ArrayList
    import java.util.ArrayList;
    ArrayList<String> stringArrayList = new ArrayList<>();
  • C++: (静态数组 和 vector)

    C++ 中也有静态数组和动态数组 vector

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <iostream>
    #include <vector>

    int main() {
    // 声明一个静态整型数组,大小为 5
    int intArray[5];

    // 声明并初始化一个静态整型数组
    int initializedIntArray[] = {1, 2, 3, 4, 5};

    // 声明一个动态数组 vector
    std::vector<int> intVector;
    return 0;
    }

数组的基本操作 (Operations)

数组最常用的基本操作包括:

  1. 访问元素 (Access): 通过索引快速访问数组中的元素。

    • Python: array[index]
    • Java: array[index]
    • C++: array[index]
    1
    2
    3
    numbers = [10, 20, 30]
    first_number = numbers[0] # 访问索引为 0 的元素,结果为 10
    print(first_number)
  2. 插入元素 (Insert): 在数组中插入新的元素。 注意:静态数组中,插入和删除操作通常效率较低,因为可能需要移动大量元素来保持数组的连续性。 动态数组 (如 Python 的 list, Java 的 ArrayList, C++ 的 vector) 在一定程度上优化了插入和删除操作,但仍然可能涉及到元素的移动。

    • Python (List - 动态数组): list.insert(index, element), list.append(element) (在末尾添加)
    • Java (ArrayList - 动态数组): arrayList.add(index, element), arrayList.add(element) (在末尾添加)
    • C++ (vector - 动态数组): vector.insert(iterator position, element), vector.push_back(element) (在末尾添加)
    1
    2
    3
    4
    numbers = [10, 20, 30]
    numbers.insert(1, 15) # 在索引 1 的位置插入 15,数组变为 [10, 15, 20, 30]
    numbers.append(40) # 在末尾添加 40,数组变为 [10, 15, 20, 30, 40]
    print(numbers)
  3. 删除元素 (Delete): 从数组中删除元素。 同样,在静态数组中删除操作也可能效率较低。

    • Python (List - 动态数组): list.remove(element) (删除指定值的第一个元素), list.pop(index) (删除指定索引的元素)
    • Java (ArrayList - 动态数组): arrayList.remove(index), arrayList.remove(Object element)
    • C++ (vector - 动态数组): vector.erase(iterator position), vector.pop_back() (删除末尾元素)
    1
    2
    3
    4
    numbers = [10, 15, 20, 30, 40]
    numbers.remove(15) # 删除第一个值为 15 的元素,数组变为 [10, 20, 30, 40]
    numbers.pop(2) # 删除索引为 2 的元素 (即 30),数组变为 [10, 20, 40]
    print(numbers)
  4. 修改元素 (Modify): 修改数组中指定索引位置的元素的值。

    • Python: array[index] = new_value
    • Java: array[index] = new_value
    • C++: array[index] = new_value
    1
    2
    3
    numbers = [10, 20, 30]
    numbers[1] = 25 # 将索引 1 的元素修改为 25,数组变为 [10, 25, 30]
    print(numbers)
  5. 遍历数组 (Traverse): 访问数组中的每个元素,通常使用循环结构。

    • Python: for element in array:, for i in range(len(array)):
    • Java: for (element : array), for (int i = 0; i < array.length; i++)
    • C++: for (element : array), for (int i = 0; i < array_length; i++)
    1
    2
    3
    4
    5
    6
    numbers = [10, 20, 30, 40, 50]
    for number in numbers:
    print(number) # 依次打印数组中的每个元素

    for i in range(len(numbers)):
    print(f"索引 {i} 的元素是: {numbers[i]}") # 打印索引和元素值

适用场景 (Use Cases)

数组由于其高效的访问速度和简单的结构,被广泛应用于各种场景:

  1. 存储和处理大量同类型数据: 例如,存储学生成绩列表、商品价格列表、图像像素数据等。
  2. 作为其他数据结构的基础: 许多更复杂的数据结构(如栈、队列、哈希表等)的实现都离不开数组。
  3. 实现各种算法: 例如,排序算法(冒泡排序、选择排序、插入排序等)、查找算法(线性查找、二分查找)等。
  4. 科学计算和工程应用: 在数学建模、物理模拟、图像处理、信号处理等领域,数组是进行数值计算和数据分析的重要工具。

总结

数组是一种最基础、最重要的数据结构。 它提供了在连续内存空间中存储和访问相同类型元素的高效方式。 理解数组的原理、操作和适用场景,是学习更复杂数据结构和算法的基础。 虽然数组在插入和删除操作上可能效率较低,但在访问元素方面具有无可比拟的优势,因此在各种编程场景中都扮演着重要的角色。


数组 (Array)
https://god23bin.github.io/unreal-engine-blog/2025/01/01/cs/ds/ds-for-beginner/basic-ds/数组 (Array)/
作者
god23bin
发布于
2025年1月1日
许可协议