【Getting Started】-数据结构介绍-Introduction to Data Structures

文章目录

  • 数组-Arrays
  • 动态数组-Dynamic Arrays
  • 遍历-Iterating
  • 插入和删除-Inserting and Erasing
  • Strings
  • Pairs
  • C++ Tuples

数据结构是指用来组织和存储数据的方式,以便对其进行高效操作。在 C++ 中,标准模板库(STL)提供了多种数据结构,帮助以不同的方式管理数据。

每种数据结构对不同操作的支持效率不同,有的结构使得元素访问非常快速,而有些则优化了元素的添加或删除。

C++ 标准库的数据结构被设计用来存储任何类型的数据。我们在声明数据结构时,通过在尖括号<>中指定所需的数据类型,如下所示:

vector<string> v;

这将创建一个只能存储 string 类型对象的 vector 结构。

以下的示例中,我们主要使用 int 数据类型,但请注意,你可以使用任何数据类型,包括 string 或用户定义的结构体。

几乎所有标准库的数据结构都支持以下方法:

  • size():返回数据结构中元素的个数。
  • empty():如果数据结构为空,返回 true,否则返回 false

数组-Arrays

资料-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 循环)
  • 全局声明数组
  • 使用一个空的初始化器列表(i.e. 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 接受一个迭代器、一个计数和一个值作为参数,将迭代器开始的指定数量的元素设置为给定的值。
它适用于需要填充固定数量元素的场景。

动态数组-Dynamic Arrays

资料-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,5>)、动态数组的静态数组(例如vector>)等等。

遍历-Iterating

资料-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
}

插入和删除-Inserting and Erasing

在 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)

Strings

资料-resources

  • 4.17 - An introduction to std::string
  • Reference - std::string

一些基础问题可能涉及用字符串做一些事情,比如:

  • 从标准输入读取字符串
  • 知道怎样使用 g e t l i n e getline getline c i n cin cin
  • 知道如何对字符串进行排序、连接字符串、遍历字符串的字符
  • 获取字符串的第 i i i 个字符
  • 怎么样通过 s u b s t r substr substr 获取子串

Pairs

如果我们想在平面上存储一组点,那么我们可以使用一个pair 容器。

对于这种情况,vector>vector>都足够了,但 pair 也可以存储两个不同类型的元素。

  • pairp:创建一个包含两个元素的 pair 对,第一个元素为 type1,第二个元素为 type2
  • make_pair(a, b):返回一个值为 abpair
  • {a, b}: 在 C++11 及以上版本中,这可以用来创建一个 pair 对,这比 make_pair(a , b)更容易编写
  • pair.firstpair 对的第一个元素
  • pair.secondpair 对的第二个元素
#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;
}

C++ Tuples

我们可以用类似 pair> 的结构来存储超过两个值,但当需要存储大量元素时,这种做法会变得很混乱。在这种情况下,使用 元组(tuple)可能会更加方便。

元组的定义
tuple t: 创建一个包含 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;
}

你可能感兴趣的:(#,Bronze(青铜组),数据结构,程序设计竞赛,信息学奥赛,C/C++,USACO)