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(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);
}
posted @ 2021-12-13 01:06  dutrmp19  阅读(71)  评论(0)    收藏  举报