数组 (Array)
数组 (Array)
概念:连续内存空间存储相同类型元素的集合
想象一下,你有一排整齐的柜子,每个柜子的大小都一样,并且都用来存放同一种类型的物品,比如书。 数组 (Array) 就像这样一排连续的柜子,它们在计算机的内存中占据着一块连续的空间,并且只能存放相同类型的数据。
- 连续内存空间: 数组中的元素在内存中是一个挨着一个排列的,中间没有空隙。 这就像柜子是紧密排列在一起的,而不是分散在房间各处。这种连续性是数组高效访问元素的基础。
- 相同类型元素: 一个数组只能存储同一种类型的数据,例如,整型数组只能存储整数,字符串数组只能存储字符串,不能在一个整型数组里存放字符串。 这就像你的书柜可能用来存放书籍,但不能用来存放衣服或食物。

数组的原理:索引 (Index) 与内存地址
数组之所以能够快速访问元素,关键在于它的 索引 (Index) 和 内存地址 的关系。
- 索引: 数组中的每个位置都有一个编号,这个编号就是索引,通常从 0 开始计数。 例如,第一个位置的索引是 0,第二个位置的索引是 1,以此类推。
- 内存地址: 每个内存位置都有一个唯一的地址。 当我们创建一个数组时,计算机会分配一块连续的内存空间给它,并记录下数组的起始地址。
当我们需要访问数组中某个索引位置的元素时,计算机可以根据以下公式快速计算出该元素的内存地址:
元素地址 = 数组起始地址 + 索引 * 每个元素的大小
由于内存是连续的,并且每个元素大小相同,所以通过简单的加法和乘法运算,就能直接定位到目标元素的内存地址,从而实现快速访问。 这就像你知道了书架的起始位置,以及每本书的厚度,就可以快速计算出任意一本指定位置的书在书架上的位置。
数组的声明 (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)
数组最常用的基本操作包括:
访问元素 (Access): 通过索引快速访问数组中的元素。
- Python:
array[index] - Java:
array[index] - C++:
array[index]
1
2
3numbers = [10, 20, 30]
first_number = numbers[0] # 访问索引为 0 的元素,结果为 10
print(first_number)- Python:
插入元素 (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
4numbers = [10, 20, 30]
numbers.insert(1, 15) # 在索引 1 的位置插入 15,数组变为 [10, 15, 20, 30]
numbers.append(40) # 在末尾添加 40,数组变为 [10, 15, 20, 30, 40]
print(numbers)- Python (List - 动态数组):
删除元素 (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
4numbers = [10, 15, 20, 30, 40]
numbers.remove(15) # 删除第一个值为 15 的元素,数组变为 [10, 20, 30, 40]
numbers.pop(2) # 删除索引为 2 的元素 (即 30),数组变为 [10, 20, 40]
print(numbers)- Python (List - 动态数组):
修改元素 (Modify): 修改数组中指定索引位置的元素的值。
- Python:
array[index] = new_value - Java:
array[index] = new_value - C++:
array[index] = new_value
1
2
3numbers = [10, 20, 30]
numbers[1] = 25 # 将索引 1 的元素修改为 25,数组变为 [10, 25, 30]
print(numbers)- Python:
遍历数组 (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
6numbers = [10, 20, 30, 40, 50]
for number in numbers:
print(number) # 依次打印数组中的每个元素
for i in range(len(numbers)):
print(f"索引 {i} 的元素是: {numbers[i]}") # 打印索引和元素值- Python:
适用场景 (Use Cases)
数组由于其高效的访问速度和简单的结构,被广泛应用于各种场景:
- 存储和处理大量同类型数据: 例如,存储学生成绩列表、商品价格列表、图像像素数据等。
- 作为其他数据结构的基础: 许多更复杂的数据结构(如栈、队列、哈希表等)的实现都离不开数组。
- 实现各种算法: 例如,排序算法(冒泡排序、选择排序、插入排序等)、查找算法(线性查找、二分查找)等。
- 科学计算和工程应用: 在数学建模、物理模拟、图像处理、信号处理等领域,数组是进行数值计算和数据分析的重要工具。
总结
数组是一种最基础、最重要的数据结构。 它提供了在连续内存空间中存储和访问相同类型元素的高效方式。 理解数组的原理、操作和适用场景,是学习更复杂数据结构和算法的基础。 虽然数组在插入和删除操作上可能效率较低,但在访问元素方面具有无可比拟的优势,因此在各种编程场景中都扮演着重要的角色。