C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】
文章目录
- STL 代码示例
- 1、迭代器
- 2、算法
- 3、array容器示例
- 4、vector示例
- 5、deque(double ended queue,双端数组)示例
- 6、list(链表)容器
- 7、set示例
- 8、map示例
- 9、stack 示例
- 10、queue示例
- 11、priority_queue (优先级队列)示例
STL 代码示例
1、迭代器
- 迭代器可以将任意的容器抽象成一个序列,可以使用迭代器遍历容器中的元素
- 迭代器设计的目的是为了解决容器与算法之间的耦合问题,与指针类似,可以通过迭代器访问容器中的元素
- 迭代器的声明方式为:容器类型::iterator 变量名称,可以理解为一个普通的指针,比如:
- std::vector<int>::iterator it;
- std::list<int>::iterator it;
- std::map<int, int>::iterator it;
- std::set<int>::iterator it;
代码:
/*
* 迭代器示例
* 迭代器可以将任意的容器抽象成一个序列,可以使用迭代器遍历容器中的元素
* 迭代器设计的目的是为了解决容器与算法之间的耦合问题,与指针类似,可以通过迭代器访问容器中的元素* 迭代器的声明方式为:容器类型::iterator,比如:std::vector<int>::iterator it;
std::list<int>::iterator it;
std::map<int, int>::iterator it;
std::set<int>::iterator it;*/
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <list>// 打印vector元素
void printVec(const std::vector<int> &v)
{std::cout << "[";for (const auto &e : v)std::cout << e << " ";std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::vector<int> v1 {1, 2, 3, 4, 5};std::vector<int>::iterator it = v1.begin(); // 指向第一个元素std::cout << *it << std::endl;it++; // 指向第二个元素std::cout << *it << std::endl;it += 2; // 指向第四个元素std::cout << *it << std::endl;it -= 2; // 指向第二个元素std::cout << *it << std::endl;it = v1.end() - 1; // 指向最后一个元素,注意end()指向最后一个元素的下一个位置std::cout << *it << std::endl;}void test2()
{std::cout << "test2 ======================" << std::endl;std::vector<int> v1 {1, 2, 3, 4, 5};auto it = v1.begin();while (it != v1.end()){std::cout << *it << std::endl;it++; // 指向下一个元素}it = v1.begin();while (it != v1.end()){*it = 100; // 修改元素值it++;}printVec(v1);}void test3()
{std::cout << "test3 ======================" << std::endl;std::vector<int> v1 {1, 2, 3, 4, 5};// std::vector<int>::const_iterator it = v1.begin(); // 常量迭代器,只能读取元素,不能修改元素auto it = v1.cbegin(); // 如果使用auto,需要使用cbegin()函数,返回一个常量迭代器while (it != v1.end()){std::cout << *it << std::endl;it++; // 指向下一个元素}it = v1.begin(); // 重新指向第一个元素while (it != v1.end()){// *it = 100; // 报错,不能修改元素it++; // 指向下一个元素}}void test4()
{std::cout << "test4 ======================" << std::endl;std::vector<int> v1 {1, 2, 3, 4, 5};auto it = v1.rbegin(); // 返回一个反向迭代器,指向最后一个元素while (it != v1.rend()) // rend()指向第一个元素的前一个位置{std::cout << *it << std::endl;it++; // 指向下一个元素}std::list<std::string> l1 {"hello", "world", "c++"};auto it2 = l1.rbegin();std::cout << *it2 << std::endl;it2++;std::cout << *it2 << std::endl;// map 里面的元素会自动按 key 进行排序std::map<std::string, std::string> m1 {{"hello", "你好"},{"world", "世界"},{"Computer", "计算机"}};auto it3 = m1.begin();while (it3 != m1.end()){std::cout << it3->first << " : " << it3->second << std::endl;it3++;}}
int main()
{// test1();// test2();// test3();test4();return 0;
}
2、算法
- STL算法基于迭代器生成的序列
- STL提供了很多算法(例如查找、排序、计数、操作),可以对序列进行操作
- 更多请查看:https://zh.cppreference.com/w/cpp/algorithm
- 多数算法要求提供额外参数,例如:排序算法需要提供排序规则,一般使用函数指针、lambda表达式或仿函数(函数对象)
代码:
/*
* 算法示例
* STL算法基于迭代器生成的序列
* STL提供了很多算法(例如查找、排序、计数、操作),可以对序列进行操作
* 更多请查看:https://zh.cppreference.com/w/cpp/algorithm
* 多数算法要求提供额外参数,例如:排序算法需要提供排序规则,一般使用函数指针、lambda表达式或仿函数(函数对象)
*/#include <iostream>
#include <vector>
#include <algorithm> // 算法头文件
#include <list>void test1()
{std::cout << "test1 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};std::vector<int>::iterator loc = std::find(v1.begin(), v1.end(), 3); // 查找3std::cout << *loc << std::endl; // 3std::cout << *v1.end() << std::endl; // 0if (loc != v1.end())std::cout << "找到 3" << std::endl;elsestd::cout << "未找到 3" << std::endl;
}void test2()
{std::cout << "test2 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5, 1, 2, 1};int counts = std::count(v1.begin(), v1.end(), 1); // 统计1的个数std::cout << "1的个数: " << counts << std::endl;
}// 判断是否是偶数
bool isEven(int x)
{return x % 2 == 0;
}
void test3()
{std::cout << "test3 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9};int counts = std::count_if(v1.begin(), v1.end(), isEven); // 使用函数指针统计偶数个数counts = std::count_if(v1.begin(), v1.end(), [](int x){ return x % 2 == 0; }); // 使用lambda表达式统计偶数个数std::cout << "偶数个数: " << counts << std::endl;counts = std::count_if(v1.begin(), v1.end(), [](int x){ return x > 6; }); // 统计大于6的个数std::cout << "大于6的个数: " << counts << std::endl;
}void test4()
{std::cout << "test4 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5, 1, 2, 1};for (const auto &e : v1)std::cout << e << " ";std::cout << std::endl;std::replace(v1.begin(), v1.end(), 1, 100); // 将1替换为100for (const auto &e : v1)std::cout << e << " ";std::cout << std::endl;
}void test5()
{std::cout << "test5 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9};if (std::all_of(v1.begin(), v1.end(), [](int x) { return x > 5; }) ) // 所有元素都大于5std::cout << "所有元素都大于5" << std::endl;elsestd::cout << "不是所有元素都大于5" << std::endl;if (std::any_of(v1.begin(), v1.end(), [](int x) { return x > 5; }) ) // 至少有一个元素大于5std::cout << "有元素大于5" << std::endl;elsestd::cout << "没有元素大于5" << std::endl;if (std::none_of(v1.begin(), v1.end(), [](int x) { return x < 0; }) ) // 没有元素小于0std::cout << "没有元素小于0" << std::endl;elsestd::cout << "有元素小于0" << std::endl;}void test6()
{std::cout << "test6 ======================" << std::endl;std::string s1 {"hello world"};std::cout << s1 << std::endl;std::transform(s1.begin(), s1.end(), s1.begin(), ::toupper); // 转换为大写,从s1的begin到end,转换后的结果放到s1的beginstd::cout << s1 << std::endl;}
int main()
{test1();// test2();// test3();// test4();// test5();// test6();return 0;
}
3、array容器示例
- array大小固定,不可改变
- 在内存中是连续的
- 获取元素的复杂度是常数,与array元素个数无关
- 是对原始数组的封装,也可以获取原始数组的指针
- 如果数组大小固定,尽量使用array,而不是使用C++原生数组,因为array可以使用标准库的算法
代码:
/*
* array容器示例
* array大小固定,不可改变
* 在内存中是连续的
* 获取元素的复杂度是常数,与array元素个数无关
* 是对原始数组的封装,也可以获取原始数组的指针
* 如果数组大小固定,尽量使用array,而不是使用C++原生数组,因为array可以使用标准库的算法
*/#include <iostream>
#include <array> // 使用array容器
#include <algorithm>
#include <numeric> // 打印数组
void display(const std::array<int,5> &arr)
{std::cout << "[ ";for (const auto &a: arr)std::cout << a << " ";std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::array<int, 5> arr1 {1, 2, 3, 4, 5};std::array<int, 5> arr2;display(arr1);display(arr2); // 未初始化,值为随机值arr2 = {10, 20, 30, 40, 50}; // 可以直接赋值display(arr1);display(arr2); std::cout << "arr1的大小:" << arr1.size() << std::endl;std::cout << "arr2的大小:" << arr2.size() << std::endl;arr1[0] = 1000;arr1.at(1) = 2000;display(arr1);std::cout << "arr1的第一个元素:" << arr1.front() << std::endl;std::cout << "arr1的最后一个元素:" << arr1.back() << std::endl;}void test2()
{std::cout << "test2 ======================" << std::endl;std::array<int, 5> arr1 {1, 2, 3, 4, 5};std::array<int, 5> arr2 {10, 20, 30, 40, 50};display(arr1);display(arr2);arr1.fill(0);display(arr1);display(arr2);arr1.swap(arr2);display(arr1);display(arr2);}void test3()
{std::cout << "test3 ======================" << std::endl;std::array<int, 5> arr1 {1, 2, 3, 4, 5};int *ptr = arr1.data(); // 返回数组的首地址std::cout << ptr << std::endl;std::cout << *ptr << std::endl;*ptr = 1000;display(arr1);
}void test4()
{std::cout << "test4 ======================" << std::endl;std::array<int, 5> arr1 {3,1,4,2,5};display(arr1);std::sort(arr1.begin(), arr1.end());display(arr1);
}void test5()
{std::cout << "test5 ======================" << std::endl;std::array<int, 5> arr1 {3,6,4,2,5};std::array<int, 5>::iterator min_val = std::min_element(arr1.begin(), arr1.end());auto max_val = std::max_element(arr1.begin(), arr1.end());std::cout << "min: " << *min_val << std::endl;std::cout << "max: " << *max_val << std::endl;
}void test6()
{std::cout << "test6 ======================" << std::endl;std::array<int, 5> arr1 {3,6,2,2,5};auto adjacent = std::adjacent_find(arr1.begin(), arr1.end()); // 查找相邻的两个相同的元素if (adjacent != arr1.end())std::cout << "adjacent: " << *adjacent << std::endl;elsestd::cout << "没有找到相邻的两个相同的元素" << std::endl;}void test7()
{std::cout << "test7 ======================" << std::endl;std::array<int, 5> arr1 {1,2,3,4,5};int sum = std::accumulate(arr1.begin(), arr1.end(), 0); // 求和std::cout << "sum: " << sum << std::endl;}void test8()
{std::cout << "test8 ======================" << std::endl;std::array<int, 10> arr1 {1,2,3,4,5,5,5,5,5,5};int counts = std::count(arr1.begin(), arr1.end(), 5); // 统计5的个数std::cout << "5一共出现了" << counts << "次" << std::endl;
}
int main()
{// test1();// test2();// test3();// test4();// test5();// test6();// test7();test8();return 0;
}
4、vector示例
- vector是一个动态数组,可以随意增加元素
- 与array一样,vector在内存中是连续的,对应的内存空间会随着元素的增加而增加
- 获取元素的复杂度是常数,与vector的大小无关
- 在vector末尾增加、删除元素的复杂度是常数,与vector的大小无关
- 在vector中间增加、删除元素的复杂度是线性的,与vector的大小有关
- 可以使用迭代器和算法
代码:
/*
* vector示例
* vector是一个动态数组,可以随意增加元素
* 与array一样,vector在内存中是连续的,对应的内存空间会随着元素的增加而增加
* 获取元素的复杂度是常数,与vector的大小无关
* 在vector末尾增加、删除元素的复杂度是常数,与vector的大小无关
* 在vector中间增加、删除元素的复杂度是线性的,与vector的大小有关
* 可以使用迭代器和算法
*/#include <iostream>
#include <vector>
#include <algorithm>// 打印vector的函数模板
template <typename T>
void printVector(const std::vector<T> &v)
{std::cout << "[";for (const auto &e : v)std::cout << e << " ";std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};printVector(v1);v1 = {10, 20, 30, 40, 50}; // 可以直接赋值printVector(v1);std::vector<int> v2(10, 88); // 10个88printVector(v2);
}void test2()
{std::cout << "test2 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};printVector(v1);std::cout << "size: " << v1.size() << std::endl; // 大小std::cout << "capacity: " << v1.capacity() << std::endl; // 容量std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量v1.push_back(6); // 在尾部添加元素printVector(v1);std::cout << "size: " << v1.size() << std::endl; // 大小std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,每超出一次,容量翻倍std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量v1.shrink_to_fit(); // 释放多余的内存printVector(v1);std::cout << "size: " << v1.size() << std::endl; // 大小std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,释放多余的内存后,容量恢复到size大小std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量v1.reserve(100); // 预留100个元素的空间printVector(v1);std::cout << "size: " << v1.size() << std::endl; // 大小std::cout << "capacity: " << v1.capacity() << std::endl; // 容量,预留100个元素的空间后,容量恢复到100,直到超出100std::cout << "max_size: " << v1.max_size() << std::endl; // 最大容量
}void test3()
{std::cout << "test3 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};printVector(v1);v1[0] = 100;v1.at(1) = 200;printVector(v1);std::cout << "v1的第一个元素: " << v1.front() << std::endl;std::cout << "v1的最后一个元素: " << v1.back() << std::endl;v1.pop_back(); // 删除最后一个元素printVector(v1);
}void test4()
{std::vector<int> v1{1, 2, 3, 4, 5};printVector(v1);v1.clear(); // 清空容器printVector(v1);v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};printVector(v1);v1.erase(v1.begin(), v1.begin() + 3); // 删除前三个元素printVector(v1);// 删除所有偶数v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};std::vector<int>::iterator it = v1.begin(); // 获取迭代器while (it != v1.end()){if (*it % 2 == 0)v1.erase(it);elseit++;}printVector(v1);
}void test5()
{std::cout << "test5 ======================" << std::endl;// 交换两个vectorstd::vector<int> v1{1, 2, 3, 4, 5};std::vector<int> v2{10, 20, 30, 40, 50};printVector(v1);printVector(v2);v1.swap(v2);printVector(v1);printVector(v2);
}void test6()
{std::cout << "test6 ======================" << std::endl;std::vector<int> v1{9, 2, 5, 4, 7, 6, 8, 1, 3};printVector(v1);std::sort(v1.begin(), v1.end()); // 排序printVector(v1);
}// 判断是否为偶数
int getEven(int x)
{return x % 2 == 0;
}void test7()
{std::cout << "test7 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};std::vector<int> v2{10, 20};printVector(v1);printVector(v2);std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); // 拷贝printVector(v1);printVector(v2);v1 = {1, 2, 3, 4, 5};v2 = {10, 20};// std::copy_if(v1.begin(),v1.end(),std::back_inserter(v2),getEven); // 拷贝偶数std::copy_if(v1.begin(), v1.end(), std::back_inserter(v2), [](int x){ return x % 2 == 0; }); // 使用lambda表达式printVector(v1);printVector(v2);
}void test8()
{std::cout << "test8 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5};std::vector<int> v2{10, 20, 30, 40, 50};std::vector<int> v3;std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3),[](int x, int y){ return x + y; }); // 加法// std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::plus<int>()); // 使用内置的加法函数std::cout << "v1 + v2 = " << std::endl;printVector(v3);v3.clear(); // 清空容器std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3),[](int x, int y){ return x * y; }); // 乘法// std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(v3), std::multiplies<int>()); // 使用内置的乘法函数std::cout << "v1 * v2 = " << std::endl;printVector(v3);
}void test9()
{std::cout << "test9 ======================" << std::endl;std::vector<int> v1{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};std::vector<int> v2{100, 200, 300, 400};printVector(v1);printVector(v2);auto it = std::find(v1.begin(), v1.end(), 5); // 查找5第一次出现的位置if (it != v1.end()){std::cout << "找到了:5 " << std::endl;v1.insert(it, v2.begin(), v2.end()); // 插入}else{std::cout << "没有找到" << std::endl;}printVector(v1);
}
int main()
{// test1();// test2();// test3();// test4();// test5();// test6();// test7();// test8();test9();return 0;
}
5、deque(double ended queue,双端数组)示例
- 动态数组,和vector类似,但是deque是双端的,可以在头部和尾部进行插入和删除操作
- 与vector不同,deque在内存中是分段连续的,每段内存都是连续的,所以在头部和尾部插入和删除元素都很快
- 获取元素的复杂度是常数
- 在头部和尾部插入和删除元素的复杂度是常数
- 在中间插入和删除元素的复杂度是线性的
- 支持迭代器和算法
代码:
/*
* deque(double ended queue,双端数组)示例
* 动态数组,和vector类似,但是deque是双端的,可以在头部和尾部进行插入和删除操作
* 与vector不同,deque在内存中是分段连续的,每段内存都是连续的,所以在头部和尾部插入和删除元素都很快
* 获取元素的复杂度是常数
* 在头部和尾部插入和删除元素的复杂度是常数
* 在中间插入和删除元素的复杂度是线性的
* 支持迭代器和算法
*/
#include <iostream>
#include <deque>
#include <vector>
#include <algorithm>// 用于显示deque的函数模板
template <typename T>
void display(const std::deque<T> &d)
{std::cout << "[ ";for (const auto &item:d )std::cout << item << " ";std::cout << "]";std::cout << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::deque<int> d1{1, 2, 3, 4, 5};display(d1);std::deque<int> d2 (10,100);display(d2);d2[0] = 99;d2.at(1) = 88;display(d2);
}void test2()
{std::cout << "test2 ======================" << std::endl;std::deque<int> d1 {0,0,0,0};display(d1);d1.push_back(10);d1.push_back(20);display(d1);d1.push_front(100);d1.push_front(200);display(d1);std::cout << "第一个元素: " << d1.front() << std::endl;std::cout << "最后一个元素: " << d1.back() << std::endl;std::cout << "大小: " << d1.size() << std::endl;d1.pop_back();d1.pop_front();display(d1);
}void test3()
{std::cout << "test3 ======================" << std::endl;std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};std::deque<int> d2;// 将vector中的偶数放入deque后,奇数放入deque前for (const auto &item:v1){if (item % 2 == 0)d2.push_back(item);elsed2.push_front(item);}display(d2);
}void test4()
{std::cout << "test4 ======================" << std::endl;std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};std::deque<int> d2;// 将vector中的元素放到d2后for (const auto &item:v1)d2.push_back(item);display(d2);d2.clear(); // 清空deque// 将vector中的元素放到d2前for (const auto &item:v1)d2.push_front(item);display(d2);}void test5()
{std::cout << "test5 ======================" << std::endl;std::vector<int> v1 {1,2,3,4,5,6,7,8,9,10};std::deque<int> d2;// 使用std::copy实现test4效果std::copy(v1.begin(), v1.end(), std::back_inserter(d2));display(d2);d2.clear(); // 清空dequestd::copy(v1.begin(), v1.end(), std::front_inserter(d2));display(d2);
}
int main()
{// test1();// test2();// test3();// test4();test5();return 0;
}
6、list(链表)容器
- 动态大小
- list是一个双向链表,支持快速的插入和删除操作
- list不支持随机访问,不支持下标运算符
代码:
/*
* list(链表)容器
* 动态大小
* list是一个双向链表,支持快速的插入和删除操作
* list不支持随机访问,不支持下标运算符
*/#include <iostream>
#include <list>
#include <algorithm>// 打印list的函数模板
template <typename T>
void printList(const std::list<T> &l)
{std::cout << "[";for (const auto &e : l)std::cout << e << " ";std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::list<int> l1 {1, 2, 3, 4, 5};printList(l1);std::list<std::string> l2;l2.push_back("hello");l2.push_back("world");printList(l2);std::list<int> l3;l3 = {1,2,3,4,5,6,7,8,9,10};printList(l3);std::list<int> l4 (10,88);printList(l4);}void test2()
{std::cout << "test2 ======================" << std::endl;std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};printList(l1);std::cout << "第一个元素: " << l1.front() << std::endl;std::cout << "最后一个元素: " << l1.back() << std::endl;std::cout << "大小: " << l1.size() << std::endl;l1.clear();printList(l1);std::cout << "大小: " << l1.size() << std::endl;
}void test3()
{std::cout << "test3 ======================" << std::endl;std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};printList(l1);l1.resize(5); // 缩小到5个元素printList(l1);
}void test4()
{std::cout << "test4 ======================" << std::endl;std::list<int> l1 {1,2,3,4,5,6,7,8,9,10};printList(l1);// 找到第一个5,然后在5前面追加一个100std::list<int>::iterator it = std::find(l1.begin(), l1.end(), 5);if (it != l1.end())l1.insert(it, 100);printList(l1);std::list<int> l2 {1000, 2000, 3000};// 将l2中的元素插入到l1中l1.insert(it, l2.begin(), l2.end());printList(l1);std::advance(it, -2); // it向前移动2个位置std::cout << *it << std::endl;l1.erase(it); // 删除it指向的元素,也就是2000printList(l1);
}void test5()
{std::cout << "test5 ======================" << std::endl;std::list<int> l1 {3,5,2,10,7,9,8,1,4,6};printList(l1);l1.sort();printList(l1);}
int main()
{// test1();// test2();// test3();// test4();test5();return 0;
}
7、set示例
- set是一种关联式容器
- 根据元素的值,自动排序,重复元素会被自动去重
- 不支持随机访问,不支持下标运算符
- 支持各种迭代器和算法
代码:
/*
* set示例
* set是一种关联式容器
* 根据元素的值,自动排序,重复元素会被自动去重
* 不支持随机访问,不支持下标运算符
* 支持各种迭代器和算法*/
#include <iostream>
#include <set>// 用于显示set的函数模板
template <typename T>
void printSet(const std::set<T> &s)
{std::cout << "[";for (const auto &e : s)std::cout << e << " ";std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::set<int> s1{1, 2, 3, 4, 5};printSet(s1);s1 = {1,1,1,2,2,2,3,3,3}; // 重复元素会被自动去重printSet(s1);s1.insert(10); s1.insert(0);printSet(s1);if (s1.count(10)) // count返回1表示找到,返回0表示未找到std::cout << "找到10" << std::endl;elsestd::cout << "未找到10" << std::endl;auto it = s1.find(10); // find返回迭代器,如果找到,返回迭代器指向该元素,否则返回end()if (it != s1.end())std::cout << "找到" << *it << std::endl;s1.clear();printSet(s1);
}void test2()
{std::cout << "test2 ======================" << std::endl;std::set<std::string> s1 {"A", "B", "C", "D", "E"};printSet(s1);auto result = s1.insert("F"); // insert返回一个pair,第一个元素是迭代器,指向插入的元素,第二个元素是bool,表示是否插入成功printSet(s1);std::cout << std::boolalpha; // boolalpha表示输出true/falsestd::cout << "first: " << *(result.first) << std::endl;std::cout << "second: " << result.second << std::endl; // 插入成功,返回trueresult = s1.insert("A"); // A 已经存在,插入失败,但是返回的迭代器指向AprintSet(s1);std::cout << std::boolalpha; // boolalpha表示输出true/falsestd::cout << "first: " << *(result.first) << std::endl;std::cout << "second: " << result.second << std::endl; // 插入失败,返回false,表示有重复元素}int main()
{// test1();test2();return 0;
}
8、map示例
- map是一种关联式容器,它的元素是key-value对(std::pair),key是唯一的,value可以重复
- map中的元素是按key自动排序的
- 使用key访问元素
代码:
/*
* map示例
* map是一种关联式容器,它的元素是key-value对(std::pair),key是唯一的,value可以重复
* map中的元素是按key自动排序的
* 使用key访问元素*/#include <iostream>
#include <map>
#include <set>// 打印map的函数模板
template <typename T1, typename T2>
void printMap(const std::map<T1, T2> &m)
{std::cout << "[";for (const auto &e : m)std::cout << e.first << ":" << e.second << " ";std::cout << "]" << std::endl;
}// map的value是set
void printMap(const std::map<std::string, std::set<int>> &m)
{std::cout << "[";for (const auto &e : m){std::cout << e.first << ":[ ";for (const auto &s : e.second)std::cout << s << " ";std::cout << "] ";}std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::map<std::string, int> m1 { // string是key,int是value{"mike", 10},{"jane", 20},{"tom", 30},};printMap(m1); // [jane:20 mike:10 tom:30 ],会自动按key排序m1.insert(std::pair<std::string, int>("anna", 100)); // 插入一个pairprintMap(m1); m1.insert(std::make_pair("bob", 200)); // 插入一个pairprintMap(m1);m1["jim"] = 300; // 如果key不存在,会自动插入一个pair,如果key存在,会更新valueprintMap(m1);m1["jim"] += 100; // 更新valueprintMap(m1);std::cout << "mike的计次:" << m1.count("mike") << std::endl; // count返回1表示找到,返回0表示未找到std::cout << "alice的计次:" << m1.count("alice") << std::endl; auto it = m1.find("jim"); // find返回迭代器,如果未找到,返回end()if (it != m1.end())std::cout << "找到" << it->first << ",value为" << it->second << std::endl;elsestd::cout << "未找到jim" << std::endl;m1.clear(); // 清空mapprintMap(m1);}void test2()
{std::cout << "test2 ======================" << std::endl;std::map<std::string, std::set<int>> student_grades { // string是key,set是value{"mike", {100, 90}},{"jane", {99, 88, 77}},{"tom", {98, 87, 76}},};printMap(student_grades);student_grades["mike"].insert(80); // 插入80分printMap(student_grades);auto it = student_grades.find("jane");if (it != student_grades.end()){it->second.erase(88); // 删除88分printMap(student_grades);}}int main()
{// test1();test2();return 0;
}
9、stack 示例
- stack 是一种容器适配器,遵循后进先出(LIFO)的原则
- stack 本身不是容器,它是基于容器实现的(如vector、list、deque等)
- 所有的操作都在栈顶进行(top)
- stack 本身没有迭代器
代码:
/*
* stack 示例
* stack 是一种容器适配器,遵循后进先出(LIFO)的原则
* stack 本身不是容器,它是基于容器实现的(如vector、list、deque等)
* 所有的操作都在栈顶进行(top)
* stack 本身没有迭代器
*/#include <iostream>
#include <stack>
#include <vector>
#include <list>
#include <deque>// 显示stack的函数模板
template <typename T>
void display(std::stack<T> s)
{std::cout << "[";while (!s.empty()){T elem = s.top(); // 读取栈顶元素std::cout << elem << " ";s.pop(); // 弹出栈顶元素}std::cout << "]" << std::endl;
}
int main()
{std::stack<int> s;for (auto i: {1,2,3,4,5})s.push(i);display(s);s.push(100); // 压入元素display(s);s.pop(); // 弹出元素s.pop();display(s);// s.clear(); // 并没有clear()方法while (!s.empty())s.pop(); // 弹出所有元素display(s);s.push(10);display(s);s.top() = 100; // 修改栈顶元素display(s);return 0;
}
10、queue示例
- queue是一种容器适配器,遵循先进先出(FIFO)的原则
- queue的底层容器可以是deque、list
- 元素只能从队尾压入,从队首弹出(排队)
- queue本身没有提供迭代器
代码:
/*
* queue示例
* queue是一种容器适配器,遵循先进先出(FIFO)的原则
* queue的底层容器可以是deque、list
* 元素只能从队尾压入,从队首弹出(排队)
* queue本身没有提供迭代器
*/#include <iostream>
#include <queue>// 显示queue的函数模板
template <typename T>
void display(std::queue<T> q)
{std::cout << "[";while (!q.empty()){T elem = q.front(); // 读取队首元素std::cout << elem << " ";q.pop(); // 弹出队首元素}std::cout << "]" << std::endl;
}int main()
{std::queue<int> q;for (auto i : {1, 2, 3, 4, 5})q.push(i);display(q);std::cout << "队首元素: " << q.front() << std::endl;std::cout << "队尾元素: " << q.back() << std::endl;q.push(100); // 压入元素display(q);q.pop(); // 弹出元素q.pop();display(q);// q.clear(); // 并没有clear()方法while (!q.empty())q.pop(); // 弹出所有元素display(q);std::cout << "size: " << q.size() << std::endl;q.push(10);q.push(20);q.push(30);display(q);std::cout << "第一个元素: " << q.front() << std::endl;std::cout << "最后一个元素: " << q.back() << std::endl;q.front() = 100; // 修改队首元素q.back() = 200; // 修改队尾元素display(q);return 0;
}
11、priority_queue (优先级队列)示例
- 允许按照优先级来插入和删除元素
- 优先级最高的元素总是位于队首(最大值在队首)
- 本身没有提供迭代器
代码:
/*
* priority_queue (优先级队列)示例
* 允许按照优先级来插入和删除元素
* 优先级最高的元素总是位于队首(最大值在队首)
* 本身没有提供迭代器*/
#include <iostream>
#include <queue>// 显示priority_queue的函数模板
template <typename T>
void display(std::priority_queue<T> pq)
{std::cout << "[";while (!pq.empty()){T elem = pq.top(); // 读取优先级最高元素std::cout << elem << " ";pq.pop(); // 弹出优先级最高元素}std::cout << "]" << std::endl;
}void test1()
{std::cout << "test1 ======================" << std::endl;std::priority_queue<int> pq;for (auto i : {3,5,8,1,2,9,4,7,6})pq.push(i);display(pq);std::cout << "大小: " << pq.size() << std::endl;std::cout << "最大值: " << pq.top() << std::endl;pq.pop(); // 弹出最大值display(pq);
}int main()
{test1();return 0;
}
相关文章:
C++进阶语法——STL 标准模板库(下)(Standard Template Library)【学习笔记(七)】
文章目录 STL 代码示例1、迭代器2、算法3、array容器示例4、vector示例5、deque(double ended queue,双端数组)示例6、list(链表)容器7、set示例8、map示例9、stack 示例10、queue示例11、priority_queue (…...
力扣:求最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 示例1: 输入: strs ["flower", "flow" , "flight"] 输出: "fl" 示例2: 输入: strs ["dog","racecar","car&…...

Redis入门04-消息通知
目录 Redis中的消息通知 命令行操作 Redis中的管道 Redis中的消息通知 Redis可以用作消息队列的中间件,它提供了一种轻量级、高性能的消息传递机制,适用于实时通信、任务队列、事件处理等各种应用。以下是有关如何使用Redis作为消息队列的一些重要信…...

关于idea使用的一些操作设置
关于idea使用的一些操作设置 1. 常用的一下设置1.1 快捷键相关1.2 配置自动生成注释(类、方法等)1.3 maven项目相关1.4 常见其他的一些操作设置 2. IntelliJ IDEA 取消param注释中参数报错提示3. idea同时打开多个文件,导航栏不隐藏、自动换行…...

CLion 2023.2.2(C ++ IDE智能代码编辑器)
CLion 2023是一款跨平台C/C集成开发环境(IDE)。它为Mac用户提供了高效的编程体验,帮助程序员们在Mac平台上进行C/C开发。 CLion 2023支持多种编译器和调试器,并具有强大的代码分析和导航功能。它还为用户提供了许多便捷的工具和插…...

企业级API资产如何管理
在当今数字化时代,API已成为企业开发和创新的重要工具,如何高效地管理和调度这些资产成为了企业发展的重要课题。API资产管理的出现,为企业解决了这一难题,通过合理管理和利用API资产,企业可以更好地推动业务发展&…...

Git https方式拉的代码IDEA推送代码报错
报错信息 fatal: could not read Username for ‘https://codehub-cn-south-1.devcloud.huaweicloud.com’: No such file or directory 18:18:39.885: [recovery_pattern] git -c credential.helper -c core.quotepathfalse -c log.showSignaturefalse push --progress --porc…...
C++ capacity()用法总结
1. 容器的容量 容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。capacity(),size(),reserve(),resize()这几个都是不太容易区分的函数 functionmeancapacity()获得容…...
TensorFlow2.0教程1-Eager
文章目录 张量极其操作1 张量自定义层一、网络层layer的常见操作二、实现自定义网络层三、网络层组合自动求导一、Gradient tapes二、记录控制流三、高阶梯度自定义训练(基础)一、Variables二、示例:拟合线性模型1、定义模型2.定义损失函数3.获取训练数据4.定义训练循环张…...

Redis学习系统(持续更新中)
RedisExample 课程介绍 目标是提供一个高效、可靠的学习和实践Redis的环境。我们将通过搭建Redis集群、实现缓存数据的持久化存储、制定缓存数据的淘汰策略以及同步缓存数据等步骤来深入了解和学习Redis的特性和功能。通过这个项目,你可以掌握Redis的核心概念和技…...
el-select获取id和name
一般选中节点只会返回:value绑定的数据给v-model中,要想获取id和name一并传给后端,需要如下几步: 1、给选择框添加点击事件 input"selectChangeParent" 2、v-for中多添加一个参数 index <el-select v-model"inputForm.pr…...
最简单的驱动程序
简介 在 Linux 内核中,Makefile 和 Kconfig 是两个重要的文件,它们分别承担着不同的作用。 Makefile Makefile 是一个文本文件,用于定义编译和构建内核的规则。它使用 make 工具来管理和自动化构建过程。Makefile 定义了编译器、链接器、编译选项、目标文件、源文件等信息…...

MFC String类的初始化学习
之前写过CString的用法; VC CString 编程实例图解_bcbobo21cn, cstring-CSDN博客 下面单独看一下CString的各种初始化方式; void CTest2View::OnDraw(CDC* pDC) {CTest2Doc* pDoc GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for nati…...

vue项目使用vite设置proxy代理,vite.config.js配置,解决本地跨域问题
vue3vite4项目,配置代理实现本地开发跨域问题 非同源请求,也就是协议(protocol)、端口(port)、主机(host)其中一项不相同的时候,这时候就会产生跨域 vite的proxy代理和vue-cli的proxy大致相同,需要在vite.config.js文件中配置&…...

实用-----七牛云绑定自定义域名 配置 HTTPS
实用-----七牛云绑定自定义域名 配置 HTTPS(无废话 无尿点) 1.访问SSL证书购买页面 https://portal.qiniu.com/certificate/ssl 2.购买免费证书 3.补全信息 注意: 域名直接输入 无需 www座机号随意填 区号需要搜索 下面为示例 4. 直接确认…...
【TS篇三】类、函数、for-of循环、类型推断
文章目录 一、类1.1 基本示例1.2 继承1.3 实例成员访问修饰符1.3.1 public 开放的1.3.2 private 私有的1.3.3 protected 受保护的1.3.4 readonly 只读的1.3.5 在参数中使用修饰符 1.4 属性的存(get)取(set)器1.5 静态成员 二、函数…...

Chatgpt批量改写文章网页版可多开软件-自动登录换号生成word或者TXT
Chatgpt批量改写文章网页版可多开软件介绍: 1、改写后生成docx格式文档和生成txt文档二选一。 2、支持原来docx文档里带图片的改写,改写伪原创后的docx里也带图片。 3、软件可以设置是否开启标题改写,可以自定义标题改写指令。 4、可以设置…...

Modelsim 使用教程(4)—— Working With Multiple Libraries
一、概述 在文中,我们将练习使用多个库。在实际的项目开发过程中,我们可能有多个库来组织设计,从第三方源代码访问IP,或者在仿真之间共享公共部分。我们将通过创建一个包含计数器设计单元的资源库来开始本文。接下来,我…...

【重要】浏览器输入地址提示【您的连接不是私密连接】解决方法
在配置 kubernetes-dashboard 时,出现您的连接不是私密连接,这种情况下,点开高级没有进一步的操作按钮,这是由于我们的证书无效导致浏览器自身防护拦截,为了接解决这个办法我们可以使用命令 thisisunsafe 强制信任该网…...

ESP-07S烧写固件记录
一,固件版本。 下面是官方默认AT指令版本,ESP-07S 的flash大小是4MB。 AT固件汇总 | 安信可科技 (ai-thinker.com) 二,烧录工具。 开发工具清单 | 安信可科技 (ai-thinker.com) 三,下载工具及连线。 使用USB转串口工具。 四&am…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...