数据结构决定数据的组织方式,以便高效地使用信息。每种数据结构都能高效支持 某些操作,而其他操作可能效率很低,甚至完全不受支持。由于各种数据结构支持的 操作不同,你应仔细判断哪一种最适合当前问题。
C++
C++ 标准库数据结构可以存储任意类型的
数据。声明数据结构时,把所需数据类型放在 <> 中,如下所示:
vector<string> v;
这会创建一个只能存储 string 类型对象的 vector。
下面的示例主要使用 int,但也可以使用任何数据类型,包括 string 和自定义结构体。
几乎所有标准库数据结构都支持 size() 和 empty() 方法。前者返回数据结构中的
元素数量;后者在数据结构为空时返回 true,否则返回 false。
Java
Python
列表
Python 默认使用列表存储数据。列表能自动调整大小以容纳更多元素,并可在 时间内在末尾添加和删除元素。列表可以按如下方式初始化:
arr = []
Python 列表是泛型的,也就是说可以存储任何数据类型,包括对象。例如,下面的 代码创建一个动态数组,并把 到 加入其中:
for i in range(1, 11): # Note that range(i, j) includes i, but does not include jarr.append(i)
在 Python 中,可以为动态数组指定初始大小。下面的代码创建一个含 个零的 动态数组。
arr = [0] * 30
遍历
可以使用普通 for 循环遍历列表中的所有元素。
arr = [1, 7, 4, 5, 2]for i in range(len(arr)):print(arr[i], end=" ")print()for element in arr:print(element, end=" ")print()
也可以使用迭代器。迭代器指向容器中的对象,从而让你遍历容器。iter(arr)
返回指向列表 arr 首个元素的迭代器。
arr = [4, 2, 0, 0, 5]it = iter(arr)print(next(it)) # 4print(next(it)) # 2print(next(it)) # 0
插入和删除
arr = []arr.append(2) # [2]arr.append(3) # [2, 3]arr.append(7) # [2, 3, 7]arr.append(5) # [2, 3, 7, 5]arr[1] = 4# sets element at index 1 to 4 -> [2, 4, 7, 5]arr.pop(1) # removes element at index 1 -> [2, 7, 5]# this remove method is O(n); to be avoidedarr.append(8) # [2, 7, 5, 8]
列表推导式
列表推导式非常实用,可以把修改或创建列表的 Python for 循环简化为一个表达式。
通用语法是:[表达式 for 元素 in 列表 if 条件]
下面的代码块给出了一个示例。
# If a number is odd, add the number times 2 into the arrayold_list = [2, 5, 3, 1, 6]new_list = []for i in old_list:if i % 2 == 1:new_list.append(i * 2)print(new_list) # [10, 6, 2]# Simplified one liner with list comprehension# Recall the form [ expression for item in list if conditional ]# expression: i * 2# list: old_list# conditional: i % 2 == 1 (only include item i if it satisfies the conditional)new_list = [i * 2 for i in old_list if i % 2 == 1]print(new_list) # [10, 6, 2]
列表推导式在算法竞赛中一个特别实用的用途,是从空格分隔的输入创建整数列表:
# Example input: 5 3 2 6 8 1# Note that the conditional in the list comprehension is optional, and defaults to True if not providedarr = [int(x) for x in input().split()]print(arr) # [5, 3, 2, 6, 8, 1]
关于列表推导式的更多信息,包括如何嵌套列表推导式来创建多维列表,请参阅以下资料。
| Resources | |||||
|---|---|---|---|---|---|
| PythonForBeginners | 基础列表推导式教程 | ||||
| GFG | 嵌套列表推导式 | ||||
数对
如果要存储二维平面上的一组点,可以使用由数对组成的动态数组。
虽然 Python 没有专门表示数对的类,但含两个元素的 元组 几乎提供了完全相同的功能。唯一的问题是元组不可变,因此无法修改其中的元素。
另一方面,Python 内置了对元组的比较支持。比较时先比较两个元组的第一个元素, 再比较第二个元素,并依次类推。
"""Output:(5, 'asdf')5True"""p1 = (5, "asdf")print(p1)print(p1[0]) # access the first element of the tuplep2 = (6, "asdf")print(p1 < p2)
内存分配
使用数组时需要留意内存限制。USACO 的内存限制通常为 256 MB。可以按以下步骤估算 在该限制内能存储多少个值:
- 计算以字节为单位的总内存大小:256 MB 即 字节。
- 除以
int(4 字节)、long long(8 字节)等类型的字节数。例如,能存储的int数量上界为 。 - 注意程序开销会减少 可用内存,而且这种开销有时非常可观,尤其是在使用递归函数时。
小测验
如何统计 list 中的元素数量?假设该列表名为 l。
题目
这里没有题目!再次强调,固定大小的数组应足以解决几乎所有铜组问题,但动态数组、 数对和元组有时能大幅简化实现。你将在下一个模块中看到一些示例。