PrevNext

数据结构决定数据的组织方式,以便高效地使用信息。每种数据结构都能高效支持 某些操作,而其他操作可能效率很低,甚至完全不受支持。由于各种数据结构支持的 操作不同,你应仔细判断哪一种最适合当前问题。

C++

C++ 标准库数据结构可以存储任意类型的 数据。声明数据结构时,把所需数据类型放在 <> 中,如下所示:

vector<string> v;

这会创建一个只能存储 string 类型对象的 vector

下面的示例主要使用 int,但也可以使用任何数据类型,包括 string 和自定义结构体。

几乎所有标准库数据结构都支持 size()empty() 方法。前者返回数据结构中的 元素数量;后者在数据结构为空时返回 true,否则返回 false

Java

Python

列表

Python 默认使用列表存储数据。列表能自动调整大小以容纳更多元素,并可在 O(1)\mathcal{O}(1) 时间内在末尾添加和删除元素。列表可以按如下方式初始化:

arr = []

Python 列表是泛型的,也就是说可以存储任何数据类型,包括对象。例如,下面的 代码创建一个动态数组,并把 111010 加入其中:

for i in range(1, 11): # Note that range(i, j) includes i, but does not include j
arr.append(i)

在 Python 中,可以为动态数组指定初始大小。下面的代码创建一个含 3030 个零的 动态数组。

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)) # 4
print(next(it)) # 2
print(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 avoided
arr.append(8) # [2, 7, 5, 8]

列表推导式

列表推导式非常实用,可以把修改或创建列表的 Python for 循环简化为一个表达式。 通用语法是:[表达式 for 元素 in 列表 if 条件]

下面的代码块给出了一个示例。

# If a number is odd, add the number times 2 into the array
old_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 provided
arr = [int(x) for x in input().split()]
print(arr) # [5, 3, 2, 6, 8, 1]

关于列表推导式的更多信息,包括如何嵌套列表推导式来创建多维列表,请参阅以下资料。

Resources
PythonForBeginners基础列表推导式教程
GFG嵌套列表推导式

数对

如果要存储二维平面上的一组点,可以使用由数对组成的动态数组。

虽然 Python 没有专门表示数对的类,但含两个元素的 元组 几乎提供了完全相同的功能。唯一的问题是元组不可变,因此无法修改其中的元素。

另一方面,Python 内置了对元组的比较支持。比较时先比较两个元组的第一个元素, 再比较第二个元素,并依次类推。

"""
Output:
(5, 'asdf')
5
True
"""
p1 = (5, "asdf")
print(p1)
print(p1[0]) # access the first element of the tuple
p2 = (6, "asdf")
print(p1 < p2)

内存分配

使用数组时需要留意内存限制。USACO 的内存限制通常为 256 MB。可以按以下步骤估算 在该限制内能存储多少个值:

  1. 计算以字节为单位的总内存大小:256 MB 即 256106256\cdot 10^6 字节。
  2. 除以 int(4 字节)、long long(8 字节)等类型的字节数。例如,能存储的 int 数量上界为 2561064=64106\frac{256\cdot 10^6}{4}=64\cdot 10^6
  3. 注意程序开销会减少 可用内存,而且这种开销有时非常可观,尤其是在使用递归函数时。

小测验

如何统计 list 中的元素数量?假设该列表名为 l

Question 1 of 3

题目

这里没有题目!再次强调,固定大小的数组应足以解决几乎所有铜组问题,但动态数组、 数对和元组有时能大幅简化实现。你将在下一个模块中看到一些示例。

Module Progress:

PrevNext