1073 字
5 分钟
竞赛算法(1) STL的使用
std::vector
构造
// O(1)std::vector<int> v1;
// O(n)std::vector<int> v2(3);std::vector<int> v3(3, 0);std::vector<int> v4(v1);std::vector<int> v5 = {1, 2, 3, 4, 5};std::vector<int> v6(v5);std::vector<int> v7(v5.begin() + 1, v5.begin() + 3); // v7 = {2, 3}不要用std::vector<bool>, 应转而使用std::vector<uint8_t>或std::vector<char>
状态
// O(1)std::vector<int> v5 = {1, 2, 3, 4, 5};v5.size(); // 5v5.capacity(); // >= 5v5.empty(); //falsev5.reserve(10); // 预留10的capacity, 减少扩容开销capacity是实际空间, size是目前大小, 这个只要亲手写过线性表就知道了, 见数据结构C1-线性表的实现.
访问元素
// O(1)v5[3]; // 4, 下标访问v5.front(); // 首元素引用, 1v5.back(); // 末元素引用, 5v5.data(); // 数组首元素指针增(添加元素)
v5.insert(v5.begin() + 3, 6); // v5: {1, 2, 3, 6, 4, 5}, 在第3个位置前插入6, O(n)
vector<vector<int>>v7;v7.push_back(vector<int>(3)); // push_back里面放构造好的元素, 均摊O(1) + O(3)(构造成本)v7.emplace_back(3); // emplace_back里面放构造函数的内容, 直接构造. 均摊O(1)删(删除元素)
v5.pop_back(); // 尾删, O(1)v5.erase(pos); // pos为迭代器, 删除pos位置的元素, O(n)v5.erase(pos1, pos2); // 两个迭代器, 删除[pos1, pos2)之间的元素.v5.clear(); // 置空改(修改元素)
v5[3] = 6;v5.front() = 6;v5.back() = 6; // v5: {6, 2, 6, 6, 4, 6}
// assign: 后面放构造函数, 相当于重构造v4.assign(v5.begin() + 1, v5.begin() + 3); // v4: {2, 6}, 取子数组, O(子数组)v5.assign(3, 6) // v5: {6, 6, 6}, O(n)
fill(v5.begin(), v5.end(), 7); // v5: {7, 7, 7}, 初始化, O(n)
v5.resize(8, 6); // v5: {7, 7, 7, 6, 6, 6, 6, 6}, 重分配大小, O(n)查(查找元素)
find(v5.begin(), v5.end(), 6); // v5.begin() + 3; 指向6第一次出现的位置其他操作
v5.assign({1, 3, 9, 6, 5, 4});sort(v5.begin(), v5.end()); // v5: {1, 3, 4, 5, 6, 9}, O(nlogn)sort(v5.rbegin(), v5.rend()); // v5: {9, 6, 5, 4, 3, 1}, O(nlogn), 等价于sort(v5.begin(), v5.end(), greater<int>());sort(v5.begin(), v5.end()); // v5: {1, 3, 4, 5, 6, 9}lower_bound(v5.begin(), v5.end(), 6); // v5.begin() + 4, (6所在迭代器). 返回第一个大于等于val的迭代器.upper_bound(v5.begin(), v5.end(), 6); // v5.begin() + 5, (9所在迭代器). 返回第一个大于val的迭代器.
v5.assign({1, 1, 1, 2, 2, 3, 6, 6, 8, 8, 9, 9});v5.erase(std::unique(v5.begin(), v5.end()), v5.end()); // v5: {1, 2, 3, 6, 8, 9}, 去除相邻重复, 一般排序后使用. O(n)
v5.erase(std::remove(v5.begin(), v5.end(), 2), v5.end()); // v5: {1, 3, 6, 8, 9}, 去除指定元素.
v4.assign({6, 6, 6});v5.swap(v4); // v5: {6, 6, 6}, v4: {1, 3, 6, 8, 9}
v4.erase(std::unique(v4.begin(), v4.end(), [](int a, int b){return (a % 2 == 0) && (b % 2 == 0);}), v4.end()); // v4 = {1, 3, 6, 9}, 去除相邻的偶数. 总是保留满足判定条件的第一个.
v4.erase(std::remove_if(v4.begin(), v4.end(), [](int a){return a % 2 == 0;}), v4.end()); // v4 = {1, 3, 9}std::unique和std::remove本身并不改变容器大小, 所以要配合erase使用.
std::pair
构造
std::pair<int, int>p1; // {0, 0}修改与访问
p1 = make_pair(2, 4); // {2, 4}auto& [x, y] = p1; // x = 2, y = 4, C++17p1.first; // 2p1.second; // 4其他注意事项
有序容器内pair会自动按先first升序, 然后second升序的顺序来储存. 无序容器需要手动定义hash
std::set
元素唯一, 按<自动升序, O(log n)操作.
有重复元素请用std::multiset, 不需要升序且需要均摊O(1)请用std::unordered_set
构造
std::set<int> st1;std::set<int> st2 = {2, 3, 5, 7, 11} // 列表构造. 自动升序排列std::set<int, greater<int>> st3; // 降序std::set<int> st4(st1); // 拷贝构造std::set<int> st5(st1.begin(), st1.end()); // 区间构造状态
st1.empty();st1.size();访问
支持迭代器遍历
for (auto& i: st2);
for (auto it = st2.begin(); it != st2.end(); ++it);
for (auto it = st2.rbegin(); it != st2.rend(); ++it); // 反向遍历
// 请注意set的迭代器不支持随机访问, 也就是说不能使用st.begin() + 1这样的写法.// 应当使用:auto it = st.begin();std::advance(it, 1); // 原地前进 1 步(O(1))auto it2 = std::next(st.begin(), 5); // 返回前进 5 步的新迭代器(O(5))auto it3 = std::prev(st.end(), 2); // 返回倒数第 2 个(O(2))增
st1.insert(3); // 返回一个std::pair类型, 第一个指向等于x的元素, 第二个返回是否插入成功st1.insert({2, 4, 6}); // voidst1.insert(st2.begin(), st2.end()); // voidst1.emplace(12); // 插入, 但是直接构造st1.merge(st2);删
st1.erase(3); // 按键删除, 返回删掉的数量, size_t类型.auto it = st1.begin();st1.erase(it); // 按迭代器删除, 返回被删元素的下一个位置的迭代器st1.erase(it, st1.end()); // 按区间删除, 返回last的迭代器st1.clear();auto temp1 = st1.extract(2);auto temp2 = st1.extract(it); // 直接摘出节点st2.insert(temp1);
st1.swap(st2);改
// 不支持, 请先删后插查
st1.find(2); // 返回迭代器st1.upper_bound(2);st1.lower_bound(2);st1.count(2); 竞赛算法(1) STL的使用
https://fuwari.vercel.app/posts/竞赛算法1-stl的使用/