【教程】Leetcode 必知必会常用数据结构与函数(C++ 版)
这篇文章总结了C++中vector和map两种常用数据结构的操作方式。主要内容包括: vector操作: 初始化方式(构造函数、列表) 容量操作(size、capacity、empty) 访问元素([]、at、front、back) 修改操作(push_back、pop_back、insert、erase、clear、swap) map操作: 多种初始化方式(列表、insert、make_pair
·
目录
注意
- 以下代码均在
using namespace std;
下执行 - 每个示例均为单独的示例。如下示例
pop_back
和push_back
均单独对res
进行操作,互不影响
// 修改 - pop_back
res.pop_back(); // 弹出最后一个元素,还剩 1,2,3,4
// 修改 - push_back
res.push_back(6); // 在末尾追加一个元素,1,2,3,4,5,6
常用数据结构及其常用操作
vecotor
- 头文件:
<vector>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | 列表初始化 | |||
初始化 | 构造函数初始化 | |||
容量 | size | 返回容器实际使用的大小 | 返回容器实际使用的大小 | |
容量 | capacity | 返回容器总容量大小 | 返回容器总容量大小 | |
容量 | empty | 判断容器是否为空 | 若为空返回 true,否则返回 false | |
访问 | [] | 查找下标的元素值,无边界检查 | 返回值 | |
访问 | at | 查找下标的元素值,有边界检查 | 返回值 | |
访问 | back | 查找尾部元素 | 返回值(引用) | |
访问 | front | 查找头部元素 | 返回值(引用) | |
操作 | push_back | 在容器末尾追加元素 | √ | |
操作 | emplace_back | 在容器末尾追加元素,比 push_back 效率更高 | √ | |
操作 | pop_back | 在容器末尾弹出最后一个元素 | √ | |
操作 | insert | 通过迭代器,在指定位置插入元素 | √ | |
操作 | earse | 移除容器中的元素 | 被删除元素下一位置的有效迭代器 | √ |
操作 | clear | 清除容器中所有元素 | √ | |
操作 | swap | 交换两个 vector 容器的内容,两个容器的大小可以不同,但数据类型要相同 | √ |
初始化
// 构造函数初始化
vector<int> res(10, -1); // 初始化 10 个 -1
vector<int> res(10); // 初始化 10 个 0
vector<int> res2; // size 为 0
// 列表初始化
vector<int> vec{}; // 使用{},此时 size 为 0
vector<int> res = {1,2,3,4,5};
vector<string> articles = {"a", "an", "the"};
// 二维 vector 初始化
vector<vector<int> > empty; // 一个空的二维 vector
vector<vector<int> > newOne(num1, vector<int>(num2, 0)); // 二维 vector 初始化,num1 和 num2 表示初始化的数量
// 初始化中的设计缺陷
vector<string> v7(10); // 这里的类型是 string,10 在此表示 10 个空字符串
vector<string> v8{10, "hi"} // 这里的类型是 string,虽然是花括号,但 10 为 int,推断出是表示数量
容量
// size
cout << res.size() << endl; // vector 的实际使用数量 5
// capacity
cout << res.capacity() << endl; // vector 的总容量 5
// empty
cout << res.empty() << endl; // 0,表示 false,即不为空;1 表示 true,即为空
访问
// []
cout << res[1] << endl; // 2
cout << res[5] << endl; // 危险!超出边界也可以访问
// at
cout << res.at(1) << endl; // 2
// cout << res.at(5) << endl; // at 会进行边界检查,超过边界抛出异常
// back
cout << res.back() << endl; // 5
// front
cout << res.front() << endl; // 1
操作
// pop_back
res.pop_back(); // 弹出最后一个元素,还剩 1,2,3,4
// push_back
res.push_back(6); // 在末尾追加一个元素,1,2,3,4,5,6
// insert
res.insert(++res.begin(), 100); // 在 vector 下标为 1 处插入元素 100,vector 变为 1 100 2 3 4 5
res.insert(++res.begin(), 2, 100); // 在 vector 下标为 1 处插入两个元素 100,vector 变为 1 100 100 2 3 4 5
res.insert(++it, {100, 100, 100}); // 在 vector 下标为 1 处插入一个列表结构,结构中包含 3 个为 100 的元素,vector 变为 1 100 100 100 2 3 4 5
res.insert(res.end(), res2.begin(), res2.end()); // 将 res2 拼接到 res 尾部
// insert 实现头插
for (int i = 0; i < 10; i++) {
icon.insert(newRes.begin(), i); // 9 8 7 6 5 4 3 2 1 0
}
// erase
res.erase(it); // 移除 it 迭代器所在位置的元素(移除一个)
res.erase(first, last); // 移除一个范围迭代器所在位置的元素,first 和 last 表示迭代器
// clear
res.clear(); // 清除容器中所有元素size 为 0, capacity 为 5
// 交换
res.swap(res2); // res 变为空,res2 变为 1 2 3 4 5
【注】push_back 可以用来实现尾插,而 insert 可以用来实现头插
遍历
map
- 头文件:
<map>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | 列表初始化 | |||
初始化 | insert 初始化时赋值 | |||
初始化 | make_pair 初始化时赋值 | |||
初始化 | [] 初始化时赋值 | |||
容量 | size | 返回容器大小 | 返回容器大小 | |
容量 | empty | 判断容器是否为空 | 若为空返回 true,否则返回 false | |
访问 | [] | 访问不存在的 key 时,自动插入该 key,size 自增 1 | ||
访问 | at | 访问不存在 key 时,抛出异常 | ||
查找 | find | 查找是否存在 key,若存在返回指向该 key 的迭代器,否则返回 end | 迭代器 | |
查找 | count | 查找 key 在 map 中的数量,由于 map 中 key 是唯一的,所以只会返回 1 | 数量值 | |
操作 | insert | 插入一个容器的元素 | √ | |
操作 | erase | 删除元素 | √ | |
操作 | clear | 清除容器中所有元素,size 变为 0 | √ |
查找 key 在 map 中的数量,由于 map 中 key 是唯一的,所以只会返回 1
初始化
// 列表初始化
map<string, int> studentGrade1 = {{"zhangsan", 100}, {"lisi", 95}, {"wangwu", 90}};
// insert 初始化并赋值
map<string, int> studentGrade2;
studentGrade2.insert({"zhangsan", 100});
studentGrade2.insert({"lisi", 95});
studentGrade2.insert({"wangwu", 90});
// make_pair 初始化并赋值
studentGrade3.insert(make_pair("zhangsan", 100));
studentGrade3.insert(make_pair("lisi", 95));
studentGrade3.insert(make_pair("wangwu", 90));
// [] 初始化并赋值
map<string, int> studentGrade3;
studentGrade4["zhangsan"] = 100;
studentGrade4["lisi"] = 95;
studentGrade4["wangwu"] = 90;
容量
// empty
cout << studentGrade2.empty() << endl; // 0,即 false,表示不为空,否则为 true
// size
cout << studentGrade2.size() << endl; // 3
访问
// []
cout << studentGrade2["zhangsan"] << endl; // 100
// [] - 访问不存在的 key 时,自动插入该 key,size 自增 1
cout << studentGrade2["zhaoliu"] << endl; // 100,此时 studentGrade2.size() 为 4
// at
cout << studentGrade2.at("lisi") << endl; // 95
// at - 访问不存在 key 时,抛出异常
// cout << studentGrade2.at("zhuqi") << endl; // 95
// find
cout << studentGrade2.find("zhangsan")->first << " " << studentGrade2.find("zhangsan")->second << endl; // zhangsan 100
查找
// find - 查找是否存在 key,若存在返回指向该 key 的迭代器,否则返回 end
cout << studentGrade2.find("zhangsan")->first << " " << studentGrade2.find("zhangsan")->second << endl; // zhangsan 100
// count - 查找 key 在 map 中的数量,由于 map 中 key 是唯一的,所以只会返回 1
cout << studentGrade2.count("zhangsan") << endl; // 1
操作
// insert
studentGrade2.insert(pair<string, int>("lili", 91));
cout << studentGrade2.at("lili") << endl; // 91
// erase - 通过 key 值删除
studentGrade2.erase("lili"); // lili 被移除
// clear - 清空 map
studentGrade2.clear();
set
- 头文件:<set>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
修改 | insert | 插入一个容器元素 | √ | |
修改 | erase | 删除一个容器元素 | √ | |
修改 | clear | 清除所有容器元素,size 变为 0 | √ |
pair
- 头文件:
<utility>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | 默认构造函数初始化 | |||
初始化 | 构造函数初始化 | |||
初始化 | 初始化列表 | |||
初始化 | make_pair | |||
访问 | first,second | 获取 pair 的第一个和第二个元素值 | 元素值 |
初始化
// 默认构造函数初始化
std::pair<int, double> p1;
// 构造函数初始化
std::pair<int, double> p2(1, 2.0);
// 初始化列表
std::pair<int, double> p3{1, 2.0};
// make_pair
auto p4 = std::make_pair(1, 2.0);
访问
cout << p3.first << endl; // 1
cout << p3.second << endl; // 2
tuple
- 头文件:
<tuple>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | make_tuple 初始化 | |||
初始化 | 构造函数初始化 | |||
初始化 | 初始化列表 | |||
访问 | get<idx>(tupleName) | 获取 idx 位置上的 tuple 值 | 元素值 |
初始化
// make_tuple 初始化
auto myTuple = std::make_tuple(10, 3.14, 'a');
// 构造函数初始化
std::tuple<int, double, char> myTuple(10, 3.14, 'a');
// 初始化列表初始化
std::tuple<int, double, char> myTuple{10, 3.14, 'a'};
// tie 初始化
int a = 10;
double b = 3.14;
char c = 'a';
std::tuple<int, double, char> myTuple = std::tie(a, b, c);
访问
// 访问 tuple 的元素,0,1,2 是索引下标
std::get<0>(myTuple); // 10
std::get<1>(myTuple); // 3.14
std::get<2>(myTuple); // a
string
- 头文件:
<string>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | 字面量初始化 | |||
初始化 | 构造函数初始化 | |||
初始化 | 列表初始化 | |||
容量 | size | 返回字符串长度 | 字符串长度 | |
容量 | length | 返回字符串长度,等同于 size | 字符串长度 | |
容量 | capacity | 返回分配的大小 | 字符串容量 | |
容量 | empty | 判断是否为空字符串 | 若为空返回 true,否则返回 false | |
容量 | [] | 返回字符串下标所对应的字符,无边界检查 | 字符 | |
容量 | at | 返回字符串下标所对应的字符,有边界检查 | 字符 | |
容量 | back | 返回最后一个字符 | 字符值 | |
容量 | front | 返回第一个字符 | 字符 | |
修改 | += | 追加字符(串) | 字符串 | √ |
修改 | append | 追加字符(串) | 字符串 | √ |
修改 | push_back | 追加字符 | √ | |
修改 | pop_back | 弹出最后一个字符 | √ | |
修改 | insert | 通过迭代器,在指定位置插入字符(串) | 字符串 | √ |
修改 | erase | 移除 string 中的字符(串) | 字符串 | √ |
修改 | clear | 清空字符串 | 字符串 | √ |
修改 | replace | 替换字符(串) | 字符串 | √ |
特殊操作 | swap | 交换两个 string 容器的内容,两个容器的大小可以不同 | √ | |
特殊操作 | c_str | 获取 c 风格字符串 | 新字符串 | × |
特殊操作 | find | 在字符串中查找字符(串) | 第一次匹配的下标 | |
特殊操作 | find_first_of | 查找子串中任意字符第一次在父串中出现的下标 | 第一次匹配的下标 | |
特殊操作 | find_last_of | 查找子串中任意字符最后一次在父串中出现的下标 | 最后一次匹配的下标 | |
特殊操作 | find_first_not_of | 查找父串中不属于子串的任意字符第一次出现的下标 | 满足条件的下标 | |
特殊操作 | find_last_not_of | |||
特殊操作 | substr | 截取子串 | 截取的子串 | × |
特殊操作 | compare | 比较字符串大小 | 相等则返回 ==0;!=0,表示字符串不相等;<0 表示 str1 的第一个不相同字符小于 str2 的第一个不相同字符,或 str1 短于 str2;>0 反之 | |
特殊操作 | npos | 静态常量,字符串长度最大值,用于 find 操作中,没有找到子串时的比较 |
初始化
// 字面量初始化
string str1 = "Literal Initialization"; // 后续以 str1 和 str2 为例
// 构造函数初始化
string str2("Constructor initialization");
// 列表初始化
string str3{"List Initialization"};
// 列表初始化
string str4 = {"List Initialization"};
容量
// size
cout << str1.size() << endl; // 22,返回字节数
// length 等效于 size
cout << str1.length() << endl; // 22,返回字节数
// capacity 字符串的实际容量,该值 >= size 和 length
cout << str1.capacity() << endl; // 22,返回字节数
// empty
cout << str1.empty() << endl; // false 表示非空,true 表示空
访问
// []
cout << str1[0] << endl; // L
// at
cout << str1.at(0) << endl; // L
// front
cout << str1.front() << endl; // L
// back
cout << str1.back() << endl; // n
修改
// +=
cout << (str1 += " str1") << endl; // Literal Initialization str1
// append - 追加单个字符
cout << str1.append("L") << endl; // Literal InitializationL
// append - 追加字符串
cout << str1.append(str2) << endl; // Literal InitializationConstructor initialization
// append - 追加字符串 - 0 表示 str2 起始地址,11 表示追加的个数
cout << str1.append(str2, 0, 11) << endl; // Literal InitializationConstructor
// append - 追加字符串 - 使用迭代器
cout << str1.append(str2.begin(), str2.begin() + 11) << endl; // Literal InitializationConstructor
// 追加单个字符
str1.push_back('L'); // 错误写法:str1.push_back('L')
cout << str1 << endl; // Literal InitializationL
// 修改 - 弹出末尾字符
str1.pop_back(); // 弹出末尾的字符
cout << str1 << endl; // Literal Initializatio,n 被弹出
// insert - 指定位置插入一个字符
cout << str1.insert(8, "_") << endl; // Literal _Initialization
// insert - 指定位置插入字符串
cout << str1.insert(str1.length(), str2) << endl; // Literal InitializationConstructor initialization
// insert - 指定位置插入子串
// str1.length():要插入的位置
// str2:被插入的字符串
// 0:被插入字符串的子串起始位置
// 2:从起始位置截取的长度
cout << str1.insert(str1.length(), str2, 0, 2) << endl; // Literal InitializationCo
// 删除某个位置的元素
str.erase(); // 删除全部元素,执行后 size 为 0
str.erase(2); // 从下标为 2 的元素开始删除到结尾(包含下标 2)
str.erase(2, 1); // 删除下标为 2 位置的元素,这里的 1 表示删除的字符个数
// replace - 从 str1 第 0 位起,长度为 7 的子串被 str2 替换
cout << str1.replace(0, 7, str2) << endl; // Constructor Initialization Initialization
// replace - 从 str1 第 0 位起,长度为 7 的子串被 str2 第 0 位起,长度为 7 的子串替换
cout << str1.replace(0, 7, str2, 0, 11) << endl; // Constructor Initialization
// 支持迭代器方式
// 交换两个字符串
str1.swap(str2);
cout << str1 << " | " << str2 << endl; // onstructor Initialization | Literal Initialization
特殊操作
// c_str
const char* cString = str.c_str();
std::cout << cString << std::endl; // 输出: Hello, World!
// find - 查找子串
cout << str1.find("Initialization") << endl; // 8。**返回第一次匹配的下标**
// find - 查找子串,从指定位置(str1 的第 8 位)开始
cout << str1.find("Initialization", 8) << endl; // 8
// find - 查找子串,从指定位置(str1 的第 0 位)开始,长度为 7
cout << str1.find("Literal", 0, 7) << endl; // 0
// find_first_of - 查找子串中任意字符第一次在 str1 中出现的位置
cout << str1.find_first_of("Initialization") << endl; // 1。因为 Initialization 中 i 字符最开始出现在 Literal 的第 1 位中
// find_last_of - 查找子串中任意字符最后一次在 str1 中出现的位置
cout << str1.find_last_of("Initialization") << endl; // 21。因为 Initialization 中 n 字符最后出现在 str1 的最后一位中
// find_first_not_of - 查找 str1 中不属于子串的任意字符第一次出现的下标
cout << str1.find_first_not_of("Literal") << endl; // 7。下标 7 是空格,子串中没有空格字符
// substr - 截取子串
cout << str1.substr(0, 7) << endl; // Literal
cout << str1.substr(0) << endl; // Literal Initialization,若没有第二个参数,则表示截取一直到末尾
// compare - 比较 str1 和 str2 是否相同
cout << str1.compare(str2) << endl; // !=0,表示字符串不相等;<0 表示 str1 的第一个不相同字符小于 str2 的第一个不相同字符,或 str1 短于 str2;>0 反之
// compare - 将 Initialization 和 str1 从第 8 位开始,长度为 14 的子串比较
cout << str1.compare(8, 14, "Initialization") << endl; // 0
// compare - 比较 str1 从第 8 位开始,长度为 14 的子串和 str2 从第 12 位起,长度为 14 的子串
cout << str1.compare(8, 14, str2, 12, 14); // 0
// string::npos:静态常量,字符串长度最大值,用于 find 操作中,没有找到子串时的比较
size_t found = str.find(toFind);
if (found == std::string::npos) std::cout << "'" << toFind << "' not found in the string." << std::endl;
array
- 头文件:
<array>
- 常用操作
分类 | 小类 | 操作 | 返回值 | 原地操作 |
---|---|---|---|---|
初始化 | ||||
访问 | [] | 返回字符串下标所对应的字符,无边界检查 | 元素值 | |
访问 | at | 返回字符串下标所对应的字符,有边界检查 | 元素值 | |
访问 | front | 返回第一个字符 | 元素值 | |
访问 | back | 返回最后一个字符 | 元素值 | |
容量 | empty | 判断容器是否为空 | 若为空返回 true,否则返回 false | |
容量 | size | 返回容器长度 | 长度值 | |
操作 | fill | 用值填充容器 | √ | |
操作 | swap | 交换容器之间的内容 | √ |
初始化并赋值
array<int, 5> arr1 = {1,2,3,4,5};
访问
// [] - 下标访问,无边界限制
cout << arr1[0] << endl; // 1
cout << arr1[5] << endl; // 可以访问越界值,危险
// at - 下标访问,有边界限制
cout << arr1.at(0) << endl; // 1
cout << arr1.at(5) << endl; // 抛出异常
// front - 访问数组第一个元素
cout << arr1.front() << endl; // 1
// back - 访问数组最后一个元素
cout << arr1.back() << endl; // 5
容量
// empty - 判断容器是否为空
cout << arr1.empty() << endl; // 0,即 false,也就是不为空。反之为 true
// size - 返回容器的大小
cout << arr1.size() << endl; // 5
操作
// fill - 填充所有元素
arr1.fill(100); // 100 100 100 100 100。所有元素被 100 填充
// swap - 交换两个容器 - 要求 array 大小相同,这一点和 vector 不同
// arr1 6 7 8 0 0
// arr2 1 2 3 4 5
arr1.swap(arr2);
list
- 描述:双向链表,支持快速插入和删除,但访问速度较慢
- 常用操作
- 初始化
- 访问
- front
- back
- 容量
- empty
- size
- 修改
5. insert
6. push_back
7. pop_back
8. push_front
9. pop_front
10. swap
11. erase
12. clear - 操作
- merge
- splice
- remove
- unique
- sort
常用算法函数
排序
快速排序
- 头文件:
<algorithm>
- 注意点:不能使用 sort 对 map 或 set 进行排序,因为 map 和 set 本身就是有序的,当你向 map 或 set 中插入一个元素,map 或 set 会进行全量自排序
vector<int> vec = {3, 1, 2, 9, 5};
sort(vec.begin(), vec.end());
for( auto v : vec){
cout << v << " "; // 1 2 3 5 9
}
cout << endl;
sort(vec.begin(), vec.end(), greater()); // 降序排列
for( auto v : vec){
cout << v << " "; // 9 5 3 2 1
}
cout << endl;
数组翻转
- 头文件:
<algorithm>
vector<int> vec = {3, 1, 2, 9, 5};
reverse(vec.begin(), vec.end());
for( auto v : vec){
cout << v << " "; // 5 9 2 1 3
}
cout << endl;
int arr[] = {3, 1, 2, 9, 5};
reverse(begin(arr), end(arr)); // 这种写法针对 c 型数组这种没有迭代器的数据结构
for( auto v : vec){
cout << v << " "; // 5 9 2 1 3
}
cout << endl;
绝对值
- c 风格
- cmath 头文件中的 abs:取整数绝对值函数
- cmath 头文件中的 fabs:取浮点数绝对值函数
- c++ 11 风格:cmath 头文件中的 std::abs 取任意数值类型绝对值函数
- 示例
// abs
#include <iostream>
#include <cmath> // 包含 abs() 函数
int main() {
int num = -5;
int absoluteValue = abs(num); // 计算绝对值
std::cout << "绝对值: " << absoluteValue << std::endl; // 输出: 绝对值: 5
return 0;
}
// fabs
#include <iostream>
#include <cmath> // 包含 fabs() 函数
int main() {
double num = -3.14;
double absoluteValue = fabs(num); // 计算绝对值
std::cout << "绝对值: " << absoluteValue << std::endl; // 输出: 绝对值: 3.14
return 0;
}
// std::abs
#include <iostream>
#include <cmath>
int main() {
int intNum = -10;
float floatNum = -2.5f;
double doubleNum = -7.89;
std::cout << "int 绝对值: " << std::abs(intNum) << std::endl; // 10
std::cout << "float 绝对值: " << std::abs(floatNum) << std::endl; // 2.5
std::cout << "double 绝对值: " << std::abs(doubleNum) << std::endl; // 7.89
return 0;
}
最值
std::max 和 std::min
- 描述:比较两个数的大小
- 返回值:最值
- 头文件:
<algorithm>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int a = 10;
int b = 20;
cout << max(a, b) << endl; // 20
cout << min(a, b) << endl; // 10
cout << max(3.14, 3.15) << endl; // 3.15
cout << max('a', 'z') << endl; // z
return 0;
}
min_element,max_element 和 minmax_element
- 描述:返回一个序列中的最值
- 返回值:指向最值的迭代器
- 头文件:
<algorithm>
// 在顺序容器中取最值
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> vec{1,2,3,4,5,6,7};
cout << *(max_element(vec.begin(), vec.end())) << endl; // 7。最大值
cout << *(min_element(vec.begin(), vec.end())) << endl; // 1。最小值
// minmax_element 第一个元素(first)为最小值,第二个元素(second)为最大值
cout << *(minmax_element(vec.begin(), vec.end())).first << endl; // 1
cout << *(minmax_element(vec.begin(), vec.end())).second << endl;// 7
return 0;
}
// 在关联容器中取最值,以 map 为例
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int main() {
map<int, string> mapTest = {{1, "grade 1"}, {2, "grade 2"}, {3, "grade 3"}};
auto it = max_element(mapTest.begin(), mapTest.end()); // 默认比较 key
cout << it->first << endl; // 3
return 0;
}
求和
- 头文件:
<numeric>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
int main()
{
vector<int> nums = {1,2,3,4,5,6,7,8,9};
// 0 表示初始化 sum 的值
int sum = accumulate(nums.begin(), nums.end(), 0); // 45
cout << sum << endl;
}
查找
- 头文件:
<algorithm>
- 举例来说,假设有数据结构图 vector<tuple<int, int, int>> tempVar,此时如果我们想从 tempVar 找到符合要求的元素应该怎么做呢
#include <algorithm>
#include <tuple>
#include <vector>
using TupleType = std::tuple<char, int, int>;
// 查找完全匹配的元组
auto findTuple(const std::vector<TupleType>& vec, const TupleType& target) {
return std::find(vec.begin(), vec.end(), target);
}
// 使用示例
int main() {
std::vector<TupleType> vec = {
{'a', 1, 10},
{'b', 2, 20},
{'c', 3, 30}
};
TupleType target = {'b', 2, 20};
auto it = findTuple(vec, target);
if (it != vec.end()) {
// 找到元素
} else {
// 未找到
}
}
- 查找自定义数据类型:需要重载自定义数据类型的 ==
假设自定义数据类型为 Person
#include <iostream>
#include <vector>
#include <algorithm> // for std::find
#include <string>
struct Person {
std::string name;
int age;
// 重载 == 运算符,用于比较两个 Person 是否相等
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
将 Person 作为 vector 的参数
int main() {
std::vector<Person> people = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35}
};
Person target = {"Bob", 25};
// 使用 std::find 查找目标元素
auto it = std::find(people.begin(), people.end(), target);
if (it != people.end()) {
std::cout << "Found: " << it->name << ", " << it->age << std::endl;
} else {
std::cout << "Not found." << std::endl;
}
return 0;
}
二分查找
- 头文件:
<algorithm>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = {1,2,3,4,5,6,7,8,9};
auto pos1 = lower_bound(vec.begin(), vec.end(), 2);
auto pos2 = upper_bound(vec.begin(), vec.end(), 2);
auto flag = binary_search(vec.begin(), vec.end(), 2);
cout << "first >= 2 position " << *pos1 << endl; // 2
cout << "first > 2 position " << *pos2 << endl; // 3
cout << "is there equal 2 number " << flag << endl; // 1
}
- 若要求小于等于和小于,则使用
greater<Type>()
这个仿函数来处理
// 示例如下
// 返回 nums 中第一个小于或等于 target 元素位置的迭代器
lower_bound(nums.begin(), nums.end(), target, greater<int>());
// 返回 nums 中第一个小于 target 元素位置的迭代器
upper_bound(nums.begin(), nums.end(), target, greater<int>());
去重
- 描述:去除数列中重复的函数,但并非真正的去重,而是将重复的元素往后放,如果要实现真正的去重,就需要辅助使用 earse 来擦除
int main(){
vector<int> vec = {1,1,2,3,3,4,4,5};
auto pos = unique(vec.begin(), vec.end()); // pos 为第一个被移至末尾的重复项的迭代器
for(int v : vec) cout << v << ' '; // 1 2 3 4 5 4 4 5
cout << endl;
vec.erase(pos, vec.end());
for(int v : vec) cout << v << ' '; // 1 2 3 4 5
cout << endl;
return 0;
}
【注】类似的还有 remove 和 earse 组合使用
lower_bound,upper_bound 和 binary_search
- 描述:以上三个算法底层都采用二分查找实现,所以需要数列是有序的
- lower_bound:查找当前有序数列中,大于等于 target 的值的位置
- upper_bound:查找当前有序数列中,大于 target 的值的位置
- binary_search:查找当前有序数列中,是否存在 target,若存在则返回 1,否则返回 0
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = {1,2,3,4,5,6,7,8,9};
auto pos1 = lower_bound(vec.begin(), vec.end(), 2);
auto pos2 = upper_bound(vec.begin(), vec.end(), 2);
auto flag = binary_search(vec.begin(), vec.end(), 2);
cout << "first >= 2 position " << *pos1 << endl; // 2
cout << "first > 2 position " << *pos2 << endl; // 3
cout << "is there equal 2 number " << flag << endl; // 1
}
- 若要求小于等于和小于,则使用
greater<Type>()
这个仿函数来处理
// 示例如下
// 返回 nums 中第一个小于或等于 target 元素位置的迭代器
lower_bound(nums.begin(), nums.end(), target, greater<int>());
// 返回 nums 中第一个小于 target 元素位置的迭代器
upper_bound(nums.begin(), nums.end(), target, greater<int>());
字符串相关
数字字符转数字
- 描述:字符数字转为数值类型。之所以这么操作有效,是因为是用的数字字符的 ascii 码相减,而其他数字字符的 ascii 和 ‘0’ 的 ascii 差值正好为其他数字字符对应的整型数字
int main() {
char c = '5';
int num = '5' - '0';
cout << num << endl; // 5
return 0;
}
【注】数字字符无法使用下文中的 stoi 等函数进行转换,因为 stoi 等函数的参数要求是字符串类型
字符串转数字(含进制转换)
- 描述:字符串数字转换为数值类型
- 头文件:
<string>
- 函数分类
- stoi:转换为 int 类型
- stol:转换为 long int 类型
- stoll:转换为 long long int 类型
- stof:转换为 float 类型
- stod:转换为 double 类型
- …
- 返回值:数值
#include <iostream>
#include <string>
using namespace std;
int main() {
string strNum = "12345"; // 期望转换为 int
string strNum2 = "123456789"; // 期望转换为 long int
string strNum3 = "3.1415"; // 期望转换为 float
string strHex = "40F1"; // 期望转换为 16 进制,对应 10 进制 16625
string strBin = "100000011110001"; // 期望转换为 2 进制,对应 10 进制 16625
string strMix = "123abc"; // 混合
string strMix2 = "abc123abc"; // 混合
cout << stoi(strNum) << endl; // 12345
cout << stol(strNum2) << endl; // 123456789
cout << stof(strNum3) << endl; // 3.1415
cout << stoi(strHex, nullptr, 16) << endl; // 16625
cout << stoi(strBin, nullptr, 2) << endl; // 16625
cout << stoi(strMix) << endl; // 123。仅转换 abc 前的数字字符
// cout << stoi(strMix2) << endl; // 抛出异常
return 0;
}
数字转字符串
- 描述:数值转为字符串
- 头文件:
<string>
- 函数:to_string
- 返回值:字符串
#include <iostream>
#include <string>
using namespace std;
int main() {
int numToString = 12345;
float numToString2 = 3.1415;
cout << to_string(numToString) << endl; // "12345"
cout << to_string(numToString2) << endl; // "3.141500"
return 0;
}
大小写转换
- 头文件:
<cctyep>
- islower:判断字符是否是小写,若是则返回 true
- isupper:判断字符是否是大写,若是则返回 true
- tolower:将大写字符转换为小写,需要接收返回值
- toupper:将小写字符转换为大写,需要接收返回值
#include <cctyep>
char c = 'a';
char c1 = 'A';
cout << "is lower: " << islower(c) << endl; // 是小写,返回非零值
cout << "is lower: " << islower(c1) << endl; // 否则返回 0
// 小写转大写
// 大写转小写用 tolower()
cout << "is lower: " << islower(toupper(c)) << endl; // 0
转换字符串中英文字符大小写
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string str{"abcdefG"};
for (int i = 0; i < str.size(); i++) {
if (islower(str[i])) str[i] = toupper(str[i]);
}
cout << str << endl; // ABCDEFG
}
使用 ascii 码值来进行大小写转换。其中 A ~ Z 对应 ascii 码 65 ~ 90,a ~ z 对应 ascii 码 97 ~ 122
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string str{"abcdefG"};
for (int i = 0; i < str.size(); i++) {
if (str[i] >= 97 && str[i] <= 122) str[i] = str[i] - 32;
}
cout << str << endl; // ABCDEFG
}
字符串分割
- 描述:结合 getline 和 sstream 流来实现 c++ 字符串分割
// 字符串中仅含空格,直接用 ssteram 流分割
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
int main() {
string str = "abc 123 张三-李四";
stringstream ss(str);
vector<string> vecString;
string tempStr;
while(ss >> tempStr) {
vecString.push_back(tempStr);
}
for (auto& v : vecString) {
cout << v << endl;
}
return 0;
}
输出
abc
123
张三-李四
// 字符串中通过 , 分割字符,使用 getline + sstream
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
int main() {
string str = "abc,123,张三-李四";
stringstream ss(str);
vector<string> vecString;
string tempStr;
while(getline(ss, tempStr, ',')) {
vecString.push_back(tempStr);
}
for (auto& v : vecString) {
cout << v << endl;
}
return 0;
}
输出
abc
123
张三-李四
acm 输入输出
输入
- 输入一个字符
// 输入一个字符
// 示例:键盘输入数字 5 后回车,即可把 5 存入变量 a 中
int a;
cin >> a
- 输入固定数量一行字符
// 输入固定数量一行字符
// 示例:键盘输入 5 2 3,然后按 ctrl+z 后,再按回车
int a, b, c;
cin >> a >> b >> c;
- 输入固定大量一行或任意数量一行
// 输入固定大量一行或任意数量一行
// 示例:键盘输入 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
#include <iostream>
#include <vector>
#include <sstream>
int main() {
std::string line;
std::getline(std::cin, line); // 读取整行输入
std::vector<int> numbers;
std::istringstream iss(line); // 将字符串转换为输入流
int num;
while (iss >> num) { // 从输入流中读取数字
numbers.push_back(num); // 将数字存入 vector
}
return 0;
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)