cpp-cramming
Published on 2021-12-13 01:06 in 分类: C-CPP with dutrmp19
分类: C-CPP

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>,更为推荐的是使用 printfscanf,因为 cincout太慢了,这里只做介绍。

使用下面的语句可以让 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) > 0
    • m.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

setunordered_set 使用场景的区别就是,是否需要保证存储的 key 是有序的。比如存储身高,最后要求升序输出所有存储好的身高。

内部实现是红黑树,所以查找的复杂度是 O(logn)

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);
}

如果您有任何关于文章的建议,欢迎评论或在 GitHub 提 PR

作者:dutrmp19
本文为作者原创,转载请在 文章开头 注明出处:https://www.cnblogs.com/dutrmp19/p/15681375.html
遵循 CC 4.0 BY-SA 版权协议


posted @   dutrmp19  阅读(59)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示