cpp-cramming
cpp-cramming
Created: 2023-08-27T11:52+08:00
本文旨在迅速了解 CPP 提供的 STL api 以应付考试。
头文件
头文件很重要:
#include <iostream> // io 流
#include <cstring> // 处理 char*风格的字符串
#include <vector>
#include <stack>
#include <map> // 基于红黑树
#include <set> // 基于红黑树
#include <unordered_map> // 哈希表
#include <unordered_set> // 基于哈希的 set
#include <cmath>
#include <algorithm>
using namespace std;
输入输出
输入输出使用的头文件为 <iostream>,更为推荐的是使用 printf和 scanf,因为 cin和 cout太慢了,这里只做介绍。
使用下面的语句可以让 cin cout 变快,参考sync_with_stdio 和 cin.tie(0); cout.tie(0);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
读取输入的整数/小数
在保证以空白符分割的情况下,cin >> a,就是读入一个数到 a 里。cin >> a >> b >> c,逐个读入。
#include<iostream>
using namespace std;
int main() {
int i_var;
double d_var;
cin >> i_var >> d_var;
cout << "input int number is " << i_var << endl;
cout << "input double number is " << d_var << endl;
return 0;
}
很智能,可以自动转换输入的字符串为数字类型。以下是一个样例:
1
1234.66788
input int number is 1
input double number is 1234.67
--------------------------------
Process exited after 5.21 seconds with return value 0
请按任意键继续. .
读取输入的字符串
字符串使用 char[]存储,而不是通过 <string>使用 cpp 的类,否则会慢。
关于 <cstring>和 <string>的区别,见difference between cstring and string。
Well,
<cstring>is basically a header containing a set of functions for dealing with C-style strings (char*).<string>, on the other hand, is header that allows you to use C++-style strings (std::string), which can do a lot of if not all of the functions provided in<cstring>on their own.
直接使用 cin 流,只能拿到空格分割的字符串。
#include<iostream>
using namespace std;
int main() {
char s1[20] = {0};
char s2[20] = {0};
cin >> s1 >> s2;
cout << "s1: " << s1 << endl;
cout << "s2: " << s2 << endl;
return 0;
}
以下是一个样例,可见输入的字符串被空白符分割了。
hhh 11 445
s1: hhh
s2: 11
--------------------------------
Process exited after 4.601 seconds with return value 0
请按任意键继续. . .
使用 gets(s)就能获取一行的输入,这就是 c 的范畴了。
使用 scanf 读取 string
如果一定要使用 scanf,则需要为 string 预留空间。并且是 &s[0]而不是 &a。
//#include <algorithm>
#include <iostream>
using namespace std;
int main() {
string a;
a.resize(3);
scanf("%s", &a[0]);
cout << a << endl;
return 0;
}
algorithm
std::swap 可以交换两个元素
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
int a[2] = {0,1};
cout << "before swap\n";
cout << a[0] << endl << a[1] << endl;
swap(a[0], a[1]);
cout << "after swap\n";
cout << a[0] << endl << a[1] << endl;
return 0;
}
container
- stack
- vector
有一些函数是重复的:
size() 返回容器的大小
empty():就是 .size()==0?
erase(key/iterator): 删除对应的元素
insert(): 插入元素
emplace(): 不做要求,毕竟是 cram,放一个 element 进去。
vector
- 增:
v.push_back(value): 加到最后v.insert(iter, value): 插入到 iter 前
- 删除:
v.erase(iter): 移除对应迭代器位置的元素,返回移除后下一个元素的迭代器v.pop_back(): 删除最后一个元素v.clear(): 删除所有元素- 迭代删除:如果要删除所有值为 value 的元素,使用
it = v.erase(it)
- 改:
v[idx] = newValue*iter = newValue
- 查:没有提供
find()接口,自己迭代查。
int main(void)
{
vector<int> v;
v.push_back(1); // {1}
v.insert(v.begin(), 0); // {0, 1}
v.erase(v.begin()); // {1}
v[0] = 2; // {2}
// 展示 erase 用法
v = { 1, 2, 3, 3, 3, 4, 3 };
for (auto& i : v)
std::cout << i << std::endl;
for (auto it = v.begin(); it != v.end();) {
if (*it == 3) {
it = v.erase(it);
} else {
++it;
}
}
std::cout << "after erase" << std::endl;
for (auto& i : v)
std::cout << i << std::endl;
}
stack
我写的第一行 stack 代码:
stack s = {1,2,3}
随手一写,三个错误,cpp 有多牛就不必多说了
正确的写法:stack<int> s({1,2,3});
top(): 返回栈顶元素的引用
pop(): 弹出栈顶元素
int main() {
pair<int, int> a={1,2};
vector<int> vec_a = {1,2,3};
vec_a.push_back(4);
unordered_map<string, int> votes;
pair<string, int> p = {"Alice", 5};
votes.insert(p);
cout << a.second << endl;
cout << vec_a[0] << endl;
cout << votes["Alice"] << endl;
return 0;
}
unordered_map
基于哈希实现的 map
- 增加:直接
m[key] = value - 删除:
m.erase(key) - 修改:
m[key] = newValue - 查找:用于判断 key 是否存在于 map 中,三种方法
m.count(key) > 0m.find(key) != m.end()m.contains(key),注意只能在 c++20 或以上版本使用
int main(void)
{
// 初始化
unordered_map<string, int> strCnt = { { "hello", 2 }, { "world", 3 } };
// 遍历
for (auto& p : strCnt)
{
std::cout << p.first << p.second << std::endl;
}
// 增加一个 new <key, value>
string s = "life";
strCnt["life"] = 4;
std::cout << strCnt[s] << std::endl; // 4
// 使用 erase(key) 删除
strCnt.erase("world");
std::cout << strCnt.size() << std::endl; // 2
// 直接修改
strCnt["hello"] = 1; // cover original value
std::cout << strCnt["hello"] << std::endl; // 1
// 查找
std::cout << strCnt.count("hello") << std::endl; // 1
std::cout << strCnt.count("world") << std::endl; // 0
// std::cout << strCnt.contains("hello") << std::endl; // available in c++20
std::cout << (strCnt.find("hello") != strCnt.end()) << std::endl; // 1
return 0;
}
unordered_set
- 增:
s.insert(value) - 查:
s.find(value),返回对应的 iter,通过s.find(value) != s.end()判断找到了元素 - 删:
s.erase(it) - 改:没法改,删了再改
int main(void)
{
std::unordered_set<int> ages;
ages.insert(10);
ages.insert(12);
ages.insert(11);
for (auto & i: ages) {
std::cout << i << std::endl;
}
auto it = ages.find(10);
ages.erase(it);
}
set
set 和 unordered_set 使用场景的区别就是,是否需要保证存储的 key 是有序的。比如存储身高,最后要求升序输出所有存储好的身高。
内部实现是红黑树,所以查找的复杂度是 \(O(log_n)\)
int main(void)
{
std::set<int> ages;
ages.insert(10);
ages.insert(12);
ages.insert(11);
for (auto & i: ages) { // 将观察到有序输出
std::cout << i << std::endl;
}
auto it = ages.find(10);
ages.erase(it);
}

浙公网安备 33010602011771号