数据结构是指用来组织和存储数据的方式,以便对其进行高效操作。在 C++ 中,标准模板库(STL)提供了多种数据结构,帮助以不同的方式管理数据。
每种数据结构对不同操作的支持效率不同,有的结构使得元素访问非常快速,而有些则优化了元素的添加或删除。
C++ 标准库的数据结构被设计用来存储任何类型的数据。我们在声明数据结构时,通过在尖括号<>
中指定所需的数据类型,如下所示:
vector<string> v;
这将创建一个只能存储 string
类型对象的 vector
结构。
以下的示例中,我们主要使用 int
数据类型,但请注意,你可以使用任何数据类型,包括 string
或用户定义的结构体。
几乎所有标准库的数据结构都支持以下方法:
size()
:返回数据结构中元素的个数。empty()
:如果数据结构为空,返回 true
,否则返回 false
。资料-resources
11.16 - Intro to std::array
数组!在 C++11 中,除了普通数组外,STL 中还存在一个数组类。例如,可以使用以下代码行初始化一个包含 25 25 25 个整数的数组:
array<int, 25> arr;
数组类支持 STL 操作(如 .empty()
或 .size()
)以及普通的方括号访问运算符:
arr[5] // 访问索引为5处的元素
C++ 没有内置的内存管理。为了将数组初始化为零,您有几个选项:
for
循环(或嵌套 for
循环)int arr[25]{}
)std::fill_n(arr , 25 , 0)
or std::fill_n(arr , arr + 25 , 0)
)
std::fill
:
std::fill 接受两个迭代器和一个值作为参数,将迭代器范围内的所有元素设置为给定的值。
它通常用于填充一个已知范围,例如容器的开始到结束。
std::fill_n:
std::fill_n 接受一个迭代器、一个计数和一个值作为参数,将迭代器开始的指定数量的元素设置为给定的值。
它适用于需要填充固定数量元素的场景。
资料-resources
4.1, 4.2 - Dynamic Arrays
4.1 - Dynamic Arrays
3.1 - Vectors
11.17 - Intro to std::vector
动态数组(C++ 中的向量)支持普通数组的所有功能,并且可以调整自身大小以容纳更多元素。在动态数组中,我们还可以在 O ( 1 ) O(1) O(1) 时间内添加和删除末尾的元素。
以下代码创建了一个动态数组,并将数字 1 1 1 到 10 10 10 添加到其中:
vector<int> v;
for (int i = 1; i <= 10; i++) { v.push_back(i); }
g++ 将允许创建一个可变长度的数组:
int n;
cin >> n;
int v[n];
可变长度数组不是 C++ 标准的一部分。我们建议您为此使用 vevtor
:
// one way
vector<int> v(n);
// another way
vector<int> v;
v.resize(n);
在基于数组的竞赛问题中,我们大部分将使用一维、二维和三维静态数组。然而,我们也可以有动态数组的动态数组(例如vector
)、静态数组的动态数组(例如array
)、动态数组的静态数组(例如vector
)等等。
资料-resources
4.4 - Working With Ranges
Reference
11.18 - Intro to Iterators
遍历静态或动态数组的所有元素的一种方法是使用 for 循环。
vector<int> v{1, 7, 4, 5, 2};
for (int i = 0; i < int(size(v)); i++) { cout << v[i] << " "; }
cout << endl;
我们也可以使用迭代器。迭代器允许您通过指向容器内的对象来遍历容器。然而,它们与指针不是一回事。
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
cout << *it << " "; // prints the values in the vector using the iterator
}
这是另一种写作方式。auto(自 C++11 以来)自动推断对象的类型:
vector<int> v{1, 7, 4, 5, 2};
for (auto it = begin(v); it != end(v); it = next(it)) {
cout << *it << " "; // prints the values in the vector using the iterator
}
我们也可以使用一个 for 循环:
for (int element : v) {
cout << element << " "; // prints the values in the vector
}
在 vector 中插入和删除的时间复杂度为 O ( n ) O(n) O(n)。
vector<int> v;
v.push_back(2); // [2]
v.push_back(3); // [2, 3]
v.push_back(7); // [2, 3, 7]
v.push_back(5); // [2, 3, 7, 5]
v[1] = 4; // sets element at index 1 to 4 -> [2, 4, 7, 5]
v.erase(v.begin() + 1); // removes element at index 1 -> [2, 7, 5]
// this remove method is O(n); to be avoided
v.push_back(8); // [2, 7, 5, 8]
v.erase(v.end() - 1); // [2, 7, 5]
// here, we remove the element from the end of the list; this is O(1).
v.push_back(4); // [2, 7, 5, 4]
v.push_back(4); // [2, 7, 5, 4, 4]
v.push_back(9); // [2, 7, 5, 4, 4, 9]
cout << v[2]; // 5
v.erase(v.begin(), v.begin() + 3); // [4, 4, 9]
// this erases the first three elements; O(n)
资料-resources
一些基础问题可能涉及用字符串做一些事情,比如:
如果我们想在平面上存储一组点,那么我们可以使用一个pair
容器。
对于这种情况,vector
和 vector
都足够了,但 pair
也可以存储两个不同类型的元素。
pairp
:创建一个包含两个元素的 pair
对,第一个元素为 type1
,第二个元素为 type2
make_pair(a, b)
:返回一个值为 a
和 b
的 pair
对{a, b}
: 在 C++11 及以上版本中,这可以用来创建一个 pair
对,这比 make_pair(a , b)
更容易编写pair.first
:pair
对的第一个元素pair.second
:pair
对的第二个元素#include
#include
using namespace std;
/**
* Output:
* Testing 123
* It is possible to edit pairs after declaring them 123
* Testing curly braces
*/
int main() {
pair<string, int> pair1 = make_pair("Testing", 123);
cout << pair1.first << " " << pair1.second << endl;
pair1.first = "It is possible to edit pairs after declaring them";
cout << pair1.first << " " << pair1.second << endl;
pair<string, string> pair2{"Testing", "curly braces"};
cout << pair2.first << " " << pair2.second << endl;
}
我们可以用类似 pair
的结构来存储超过两个值,但当需要存储大量元素时,这种做法会变得很混乱。在这种情况下,使用 元组(tuple
)可能会更加方便。
元组的定义
tuple
: 创建一个包含 N
个元素的元组,每个元素的类型依次为 type1、type2、...、typeN
。
make_tuple(a, b, c, ..., d)
: 返回一个元组,元组的值按照括号中的顺序(a, b, c, ..., d)
创建。
get(t)
: 返回元组 t
中的第 i
个元素。也可以用于修改元组的元素。这个操作只能用于常量 i
。也就是说,下面这种写法是不允许的:
tuple<int, int, int> t{3, 4, 5};
int i = 1;
cout << get<i>(t) << endl; // not allowed!
tie(a, b, c, ..., d) = t
: 将元组 t
中的元素按顺序赋值给 a, b, c, ..., d
。
元组非常适合用来存储多个不同类型的元素,尤其是当我们不想使用多个 pair
嵌套时。
#include
#include
using namespace std;
/**
* Output:
* 3 4 5
* 7 4 5
* Hello world 100
*/
int main() {
int a = 3, b = 4, c = 5;
tuple<int, int, int> t = tie(a, b, c);
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
get<0>(t) = 7;
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
tuple<string, string, int> tp2 = make_tuple("Hello", "world", 100);
string s1, s2;
int x;
tie(s1, s2, x) = tp2;
cout << s1 << " " << s2 << " " << x << endl;
}