一、Python中的列表(List)
Python的列表是动态数组,内置于语言中,功能强大且易用,非常适合算法竞赛。
1. 基本概念
-
定义:列表是一个有序、可变的序列,可以存储任意类型的元素(整数、字符串、甚至其他列表等)。
-
声明方式 :
pythonmy_list = [] # 空列表 my_list = [1, 2, 3] # 包含元素的列表 mixed_list = [1, "hello", 3.14] # 混合类型
-
特点 :
- 动态大小:可以随时添加或删除元素,无需预先指定大小。
- 可变性:可以修改列表中的元素。
- 索引:支持正向索引(从0开始)和负向索引(从-1开始倒数)。
- 内存:Python列表内部是动态数组,扩容时会分配更多空间(通常是当前大小的1.5到2倍)。
2. 常用操作
以下是Python列表的核心操作,时间复杂度标注在括号中:
-
访问元素 :
my_list[i]
(O(1))pythonprint(my_list[0]) # 访问第一个元素 print(my_list[-1]) # 访问最后一个元素
-
修改元素 :
my_list[i] = value
(O(1))pythonmy_list[0] = 10 # 将第一个元素改为10
-
追加元素 :
append(value)
(均摊O(1))pythonmy_list.append(4) # 在末尾添加4
-
插入元素 :
insert(index, value)
(O(n),因为需要移动元素)pythonmy_list.insert(1, 5) # 在索引1处插入5
-
删除元素 :
-
pop(index)
:删除并返回指定索引的元素,默认删除末尾(O(1)末尾,O(n)其他位置)pythonmy_list.pop() # 删除末尾元素 my_list.pop(0) # 删除第一个元素
-
remove(value)
:删除第一个匹配的值(O(n),因为需要查找)pythonmy_list.remove(2) # 删除值为2的元素
-
-
切片 :
my_list[start:end:step]
(O(k),k是切片长度)pythonprint(my_list[1:3]) # 获取索引1到2的子列表 print(my_list[::-1]) # 反转列表
-
长度 :
len(my_list)
(O(1)) -
排序 :
sort()
(原地排序,O(n log n))或sorted()
(返回新列表)pythonmy_list.sort() # 默认升序 my_list.sort(reverse=True) # 降序 new_list = sorted(my_list) # 返回排序后的新列表
-
查找 :
value in my_list
(O(n))pythonif 3 in my_list: print("Found")
3. 高级用法
-
列表推导式 :快速生成列表。
pythonsquares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16] evens = [x for x in my_list if x % 2 == 0] # 提取偶数
-
嵌套列表 :实现二维数组(矩阵)。
pythonmatrix = [[1, 2], [3, 4]] print(matrix[0][1]) # 访问第1行第2列
注意 :二维列表初始化时要小心浅拷贝问题:
python# 错误:所有行指向同一对象 matrix = [[0] * 3] * 3 # 正确: matrix = [[0 for _ in range(3)] for _ in range(3)]
4. 竞赛中的应用
- 动态数组:Python列表适合大多数需要动态调整大小的场景,如存储输入数据。
- 栈和队列 :用
append()
和pop()
实现栈,用append()
和pop(0)
实现队列(不过pop(0)
是O(n),建议用collections.deque
优化队列操作)。 - 排序和搜索 :内置的
sort()
和sorted()
非常高效,适合排序相关问题。 - 多维数组:处理矩阵、图的邻接表等。
5. 注意事项
-
性能 :
pop(0)
和insert(0, value)
是O(n),如果需要频繁操作列表头部,考虑用collections.deque
。 -
内存:列表动态扩容可能导致内存开销,尽量预估大小。
-
浅拷贝 vs 深拷贝 :
pythona = [1, 2, 3] b = a # 浅拷贝,指向同一对象 c = a.copy() # 深拷贝(一级) import copy d = copy.deepcopy(a) # 完全深拷贝(多级嵌套)
二、C++中的列表(std::vector)
C++没有直接的"列表"概念,但std::vector
是最接近Python列表的动态数组结构,广泛用于算法竞赛。C++还有std::list
(双向链表),但竞赛中极少使用,因为链表操作较慢。
1. 基本概念
-
定义 :
std::vector
是C++标准模板库(STL)中的动态数组,支持随机访问和动态调整大小。 -
头文件 :需要包含
<vector>
。cpp#include <vector> using namespace std;
-
声明方式 :
cppvector<int> vec; // 空向量 vector<int> vec = {1, 2, 3}; // 初始化 vector<int> vec(5, 0); // 5个0
-
特点 :
- 动态大小:可以自动扩容,类似Python列表。
- 类型安全 :必须指定元素类型(如
int
、double
等)。 - 连续内存:元素存储在连续内存中,支持随机访问(O(1))。
- 扩容机制:当容量不足时,分配更大内存(通常2倍),拷贝元素,释放旧内存。
2. 常用操作
以下是std::vector
的核心操作,时间复杂度标注在括号中:
-
访问元素 :
vec[i]
或vec.at(i)
(O(1))cppcout << vec[0] << endl; // 第一个元素 cout << vec.back() << endl; // 最后一个元素
注意 :
vec[i]
不检查越界,vec.at(i)
会抛异常。 -
修改元素 :
vec[i] = value
(O(1))cppvec[0] = 10;
-
追加元素 :
push_back(value)
(均摊O(1))cppvec.push_back(4); // 在末尾添加4
-
删除元素 :
-
pop_back()
:删除末尾元素(O(1))cppvec.pop_back();
-
erase(iterator)
:删除指定位置元素(O(n),因为需要移动元素)cppvec.erase(vec.begin()); // 删除第一个元素 vec.erase(vec.begin() + 2); // 删除第3个元素
-
-
插入元素 :
insert(iterator, value)
(O(n),因为需要移动元素)cppvec.insert(vec.begin() + 1, 5); // 在索引1处插入5
-
大小和容量 :
-
size()
:返回元素个数(O(1)) -
capacity()
:返回当前分配的内存大小(O(1)) -
resize(n)
:调整大小,不足补默认值,多了截断 -
reserve(n)
:预分配内存,避免频繁扩容cppvec.reserve(100); // 预分配100个元素的空间
-
-
清空 :
clear()
(O(1),仅清空元素,不释放内存)cppvec.clear();
-
排序 :需要
<algorithm>
库的sort
函数(O(n log n))cpp#include <algorithm> sort(vec.begin(), vec.end()); // 升序 sort(vec.begin(), vec.end(), greater<int>()); // 降序
-
查找 :
find
或手动遍历(O(n))cppauto it = find(vec.begin(), vec.end(), 3); if (it != vec.end()) cout << "Found" << endl;
3. 高级用法
-
迭代器 :用于遍历或操作。
cppfor (auto it = vec.begin(); it != vec.end(); ++it) { cout << *it << " "; }
或用范围for循环(C++11):
cppfor (int x : vec) { cout << x << " "; }
-
二维向量 :实现矩阵。
cppvector<vector<int>> matrix(3, vector<int>(3, 0)); // 3x3矩阵,初始化为0 matrix[0][1] = 5; // 修改第1行第2列
-
自定义比较 :排序时可以传递比较函数。
cppsort(vec.begin(), vec.end(), [](int a, int b) { return a > b; }); // 降序
4. 竞赛中的应用
- 动态数组 :
vector
适合需要动态调整大小的场景,如存储图的邻接表。 - 栈 :用
push_back()
和pop_back()
实现栈。 - 排序和搜索 :结合
sort
和binary_search
处理有序数据。 - 矩阵和图 :二维
vector
用于表示矩阵或邻接表。
5. 注意事项
-
性能 :
push_back
均摊O(1),但扩容可能导致拷贝开销,建议用reserve
预分配空间。 -
越界访问 :
vec[i]
不检查越界,可能导致未定义行为,建议用at(i)
或检查size()
。 -
内存管理 :
clear()
不释放内存,需用shrink_to_fit()
或swap
技巧:cppvector<int>().swap(vec); // 释放内存
-
迭代器失效:插入或删除元素可能导致迭代器失效,需小心。
三、Python列表与C++ vector的对比
特性/操作 | Python List | C++ std::vector |
---|---|---|
类型 | 动态数组,内置类型 | 动态数组,STL模板类 |
元素类型 | 任意类型(动态类型) | 固定类型(静态类型) |
内存分配 | 动态扩容(1.5-2倍) | 动态扩容(通常2倍) |
访问 | O(1),支持负索引 | O(1),无负索引 |
追加 | append ,均摊O(1) |
push_back ,均摊O(1) |
插入/删除 | O(n),头部操作慢 | O(n),头部操作慢 |
切片 | 支持,O(k) | 不支持,需手动实现 |
排序 | sort() /sorted() ,O(n log n) |
std::sort ,O(n log n) |
内存管理 | 自动管理 | 需手动优化(如reserve ) |
竞赛适用性 | 简单易用,适合快速原型 | 性能更高,适合严格时间限制 |
四、算法竞赛中的建议
- 常见问题与优化 :
-
输入处理 :
-
Python:
input().split()
或list(map(int, input().split()))
。 -
C++:
cin
配合vector
。cppint n; cin >> n; vector<int> vec(n); for (int i = 0; i < n; ++i) cin >> vec[i];
-
-
性能优化 :
- Python:避免频繁的
pop(0)
,用deque
替代。 - C++:用
reserve
减少扩容,ios::sync_with_stdio(false)
加速I/O。
- Python:避免频繁的
-
调试 :
- Python:用
print
快速调试。 - C++:用
cout
或调试器,注意越界问题。
- Python:用
-