C++ STL之容器介绍(vector、list、set、map)
1 STL基本概念
- C++有两大思想,面向对象和泛型编程。
- 泛型编程指编写代码时不必指定具体的数据类型,而是使用模板来代替实际类型,这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C++泛型编程的一个杰出例子。
- STL(Standard Template Library)即标准模板库。STL通过使用模板实现了容器和算法的分离,允许程序员编写与类型无关的代码,这正是泛型编程的核心思想。
2 STL六大组件
- STL分为六大组件,分别是容器、算法、迭代器、仿函数、适配器和空间配置器。
- 容器:各种数据结构,主要用来存放数据。如
vector
、list
、map
等。 - 算法:各种常见的算法,用来处理元素。如
sort
、find
、copy
、for_each
等。 - 迭代器:连接容器和算法的桥梁
- 仿函数:行为类似函数,可作为算法的某种策略
- 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
- 空间配置器:负责空间的配置与管理
3 容器概述
- 容器分为序列式容器和关联式容器
- 序列式容器:有序集合,其内的每个元素均有确凿的位置 - 取决于插入时机和地点,与元素值无关。主要有
vector
、deque
、list
和forward_list
。 - 关联式容器:已排序集合,元素位置取决于其value(或key)和给定的某个排序准则。主要有
set
、multiset
、map
、multimap
。 -
类型 容器 迭代器 特点 序列容器 vector - 动态数组 迭代器支持随机访问
插入元素可能导致所有迭代器失效
删除元素会使指向被删除元素及之后元素的迭代器失效支持快速随机访问
但在末尾以外位置插入或删除元素效率较低deque - 双端队列 迭代器支持随机访问
插入和删除元素都可能导致迭代器失效两端都可以高效地进行插入和删除操作
随机访问效率没有vector高list - 双向链表 迭代器不支持随机访问
插入新元素不会使现有迭代器失效
删除元素只会使指向被删除元素的迭代器失效支持高效的中间插入和删除操作,但访问速度较慢 关联容器 set/multiset 插入元素不会使迭代器失效
删除元素只会使指向被删除元素的迭代器失效查找、插入和删除操作的时间复杂度为 O(log n)。 map/multimap 插入元素不会使迭代器失效
删除元素只会使指向被删除元素的迭代器失效查找、插入和删除操作的时间复杂度为 O(log n)。 容器适配器 stack - 栈 无迭代器 先进后出的数据结构 queue - 队列 无迭代器 先进先出的数据结构
4 vector
- vector是动态数组。动态扩展时,会将原数据拷贝到一块新的内存中,再释放原内存空间。
- vector迭代器支持随机访问,即可以进行+2,+3,+n操作。不支持随机访问的迭代器只能进行++操作。
- 结构图示
4.1 vector构造
vector<T> v
:默认构造vector(v.begin(), v.end())
:将[begin, end)区间的元素拷贝给本身vector(n, elem)
:将n个elem元素拷贝给本身vector(const vector &vec)
:拷贝构造- vector构造示例
-
#include <iostream>#include <string>#include <vector>int main() {// 默认构造std::vector<int> v1;// 插入数据v1.push_back(10);v1.push_back(20);v1.push_back(30);v1.push_back(40);v1.push_back(50);// 通过区间方式构造std::vector<int> v2(v1.begin(), v1.end());// 构造时放入5个100std::vector<int> v3(10, 100);// 拷贝构造std::vector<int> v4(v3);system("pause");return 0;}
-
4.2 vector赋值
vector& operator=(const vector &vec)
assign(beg, end)
:将[beg, end)区间的元素赋值给本身assign(n, elem)
:将n个elem元素赋值给本身- vector赋值示例
-
#include <iostream>#include <string>#include <vector>int main() {// 默认构造std::vector<int> v1;// 插入数据v1.push_back(10);v1.push_back(20);v1.push_back(30);v1.push_back(40);v1.push_back(50);// 通过=赋值std::vector<int> v2;v2 = v1;// 通过assign赋值一个区间的值std::vector<int> v3;v3.assign(v1.begin(), v1.end());// 通过assign赋值5个100std::vector<int> v4;v4.assign(5, 100);system("pause");return 0;}
-
4.3 vector容量和大小
empty()
: 判断容器是否为空capacity()
: 容器的容量size()
: 容器中元素个数resize(int num)
: 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。若容器变短,则末尾超出长度的元素被删除。resize(int num, const value_type& value)
: 同上,只不过在容器变长时以value填充新位置。void reserve(int len)
: 容器预留len长度的空间,预留位置不初始化,元素不可访问。预留容器的空间可以减少vector在动态扩展时的扩展次数。
4.4 vector插入和删除
push_back(elem)
: 尾部插入元素。pop_back()
: 删除尾部元素。iterator insert(pos, elem)
: 迭代器指向位置pos处插入元素elem,返回新元素的位置。iterator insert(pos, count, elem)
: 迭代器执行位置pos处插入count个元素elem,返回新元素的位置。iterator erase(pos)
: 删除迭代器pos指向的元素,返回下一个数据的位置。iterator erase(first, last)
: 删除迭代器从first带last之间的元素,返回下一个数据的位置。clear()
: 删除容器中所有元素。- 插入删除示例
-
#include <iostream>#include <string>#include <vector>#include <algorithm>void printVector(std::vector<int>& vec) {// 遍历数据std::cout << "vector: ";for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {std::vector<int> v;// 插入数据v.push_back(10);v.push_back(20);v.push_back(30);v.push_back(40);printVector(v);v.pop_back();printVector(v);v.insert(v.begin(), 1024);printVector(v);v.insert(v.begin(), 2, 520);printVector(v);// 删除v.erase(v.begin());printVector(v);system("pause");return 0;}
-
- 打印结果
-
vector: 10 20 30 40vector: 10 20 30vector: 1024 10 20 30vector: 520 520 1024 10 20 30vector: 520 1024 10 20 30请按任意键继续. . .
-
- vector插入自定义数据类型
-
#include <iostream>#include <string>#include <vector>#include <algorithm>class Person {public:Person(int code, std::string name) {mCode = code;mName = name;}int mCode;std::string mName;};void vPrint(Person data) {std::cout << "code: " << data.mCode << std::endl;std::cout << "name: " << data.mName << std::endl;}int main() {Person p1(10010, "Tom");Person p2(10020, "Jack");Person p3(10030, "Lucy");Person p4(10040, "Mary");std::vector<Person> v;// 插入数据v.push_back(p1);v.push_back(p2);v.push_back(p3);v.push_back(p4);// 通过迭代器遍历数据for (std::vector<Person>::iterator iter = v.begin(); iter != v.end(); iter++) {std::cout << "code " << (*iter).mCode << std::endl;std::cout << "name " << (*iter).mName << std::endl;}// 通过算法遍历std::for_each(v.begin(), v.end(), vPrint);system("pause");return 0;}
-
4.5 vector数据存取
at( size_type pos )
: 返回索引pos处的数据operator[]( size_type pos )
: 返回索引pos处的数据front()
: 返回容器中第一个元素back()
: 返回容器中最后一个元素- 数据存储示例
-
#include <iostream>#include <string>#include <vector>void printVector(std::vector<int>& vec) {// 遍历数据std::cout << "vector[]: ";for (int i = 0; i < vec.size(); i++) {std::cout << vec[i] << " ";}std::cout << std::endl;std::cout << "vector at: ";for (int i = 0; i < vec.size(); i++) {std::cout << vec.at(i) << " ";}std::cout << std::endl;}int main() {std::vector<int> v;// 插入数据v.push_back(10);v.push_back(20);v.push_back(30);v.push_back(40);printVector(v);system("pause");return 0;}
-
4.6 通过swap缩小容器容量
void swap( vector& other )
: 交换两个容器中的元素。常用的一个场景是缩小容器容量- 示例如下
-
#include <iostream>#include <string>#include <vector>int main() {// 默认构造std::vector<int> v1;// 插入50万个数据for (int i = 0; i < 500000; i++) {v1.push_back(i);}// 容器中元素为50万,容器容量可能为70万std::cout << "v1.size: " << v1.size() << std::endl;std::cout << "v1.cap: " << v1.capacity() << std::endl;// 后续如果要删除元素,比如只剩下3个元素了// 此时容器元素个数为3,但容器容量依然是70万,造成资源浪费v1.resize(3);std::cout << "v1.size: " << v1.size() << std::endl;std::cout << "v1.cap: " << v1.capacity() << std::endl;// 通过匿名对象交换容器// 匿名对象中的元素会被系统自动回收std::vector<int>(v1).swap(v1);// v1此时的元素个数和容量都为3std::cout << "v1.size: " << v1.size() << std::endl;std::cout << "v1.cap: " << v1.capacity() << std::endl;system("pause");return 0;}
-
5 deque
- deque是双端队列,可以在头部进行插入删除操作
- vector对于头部的插入删除效率低,数据量越大,效率越低。deque对头部的插入删除速度比vector快。vector访问元素的速度比deque快。
- deque容器的迭代器支持随机访问。
- 结构图示
- deque工作原理:deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每段缓冲区的地址。图示如下
- deque的构造、赋值、遍历、数据存取和vector基本类似,这里就不再介绍。
5.1 deque容量和大小
empty()
:判断容器是否为空。size()
:返回容器中元素个数。resize(num)
:重新指定容器的长度为num。若容器变长,则以默认值填充新位置。若容器变短,则末尾超出容器长度的元素被删除。resize(num, elem)
:同上,重新指定容器长度为num,容器变长则以elem填充。
5.2 deque插入和删除
push_back(elem)
:容器尾部插入数据。push_front(elem)
:容器头部插入数据。pop_back()
:删除容器尾部最后一个数据。pop_front()
:删除容器头部第一个容器。iterator intsert(pos, elem)
:在pos位置插入一个elem数据,返回新数据的位置。iterator intsert(pos, n, elem)
:在pos位置插入n个elem数据,返回新数据的位置。iterator intsert(pos, beg, end)
:在pos位置插入[beg, end)区间的数据,返回新数据的位置。clear()
:清空容器的所有数据。iterator erase(beg, end)
:删除[beg, end)区间的数据,返回下一个数据的位置。iterator erase(pos)
:删除pos位置的数据,返回下一个数据的位置。- 代码示例
-
#include <iostream>#include <string>#include <deque>void printDeque(std::deque<int> & de) {std::cout << "deque: ";for (std::deque<int>::iterator iter = de.begin(); iter != de.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {// 默认构造std::deque<int> d1;// 尾部插入d1.push_back(10);d1.push_back(20);d1.push_back(30);printDeque(d1);// 头部插入d1.push_front(40);d1.push_front(50);d1.push_front(60);printDeque(d1);// 删除尾部元素d1.pop_back();printDeque(d1);// 删除头部元素d1.pop_front();printDeque(d1);// insert插入std::deque<int>::iterator iter1 = d1.insert(d1.begin(), 1024);printDeque(d1);std::cout << "*iter1: " << *iter1 << std::endl;// insert插入多个元素std::deque<int>::iterator iter2 = d1.insert(d1.begin(), 2, 256);printDeque(d1);std::cout << "*iter2: " << *iter2 << std::endl;std::deque<int> d2;d2.push_back(1);d2.push_back(2);d2.push_back(3);// insert 区间插入std::deque<int>::iterator iter3 = d1.insert(d1.begin(), d2.begin(), d2.end());printDeque(d1);std::cout << "*iter3: " << *iter3 << std::endl;// 删除指定位置元素std::deque<int>::iterator iter4 = d1.begin();iter4++;std::deque<int>::iterator iter5 = d1.erase(iter4);printDeque(d1);std::cout << "*iter5: " << *iter5 << std::endl;// 删除所有元素d1.clear();system("pause");return 0;}
-
- 打印结果
-
deque: 10 20 30deque: 60 50 40 10 20 30deque: 60 50 40 10 20deque: 50 40 10 20deque: 1024 50 40 10 20*iter1: 1024deque: 256 256 1024 50 40 10 20*iter2: 256deque: 1 2 3 256 256 1024 50 40 10 20*iter3: 1deque: 1 3 256 256 1024 50 40 10 20*iter5: 3请按任意键继续. . .
-
5.3 deque排序
sort(iterator beg, iterator end)
:对beg和end区间内元素进行排序- 迭代器支持随机访问的容器都可以使用
sort
进行排序 - 代码示例
-
#include <iostream>#include <string>#include <deque>#include <algorithm>void printDeque(std::deque<int> & de) {std::cout << "deque: ";for (std::deque<int>::iterator iter = de.begin(); iter != de.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {// 默认构造std::deque<int> d1;// 尾部插入d1.push_back(10);d1.push_back(900);d1.push_back(23);d1.push_back(250);d1.push_back(18);printDeque(d1);sort(d1.begin(), d1.end());printDeque(d1);system("pause");return 0;}
-
- 结果打印
-
deque: 10 900 23 250 18deque: 10 18 23 250 900请按任意键继续. . .
-
6 stack
- stack是栈,一种先进后出的数据结构,只有一个出口。
- 栈中只有顶端元素才可以被外部使用,因此栈没有遍历操作。
- 结构图示
6.1 stack赋值操作
stack& operator=(const stack &stk)
6.2 stack数据存取
push(elem)
:向栈顶添加元素(入栈)。pop()
:从栈顶移除元素(出栈)。top()
:返回栈顶元素。
6.3 stack 大小操作
empty()
:判断栈是否为空。size()
:返回栈大小。- 使用示例
-
#include <iostream>#include <string>#include <stack>int main() {// 默认构造std::stack<int> st1;// 入栈st1.push(10);st1.push(20);st1.push(30);st1.push(40);// 获取栈顶元素std::cout << "stack top: " << st1.top() << std::endl;std::cout << "stack size: " << st1.size() << std::endl;while (!st1.empty()) {std::cout << "stack top: " << st1.top() << std::endl;// 出栈st1.pop();}std::cout << "stack size: " << st1.size() << std::endl;system("pause");return 0;}
-
- 打印结果
-
stack top: 40stack size: 4stack top: 40stack top: 30stack top: 20stack top: 10stack size: 0请按任意键继续. . .
-
7 queue
- queue是队列,一种先进先出的数据结构。
- 队列允许从一端新增元素,另一端移除元素。队列中只有队头和队尾才可以被外部使用,因此队列不允许有遍历行为。
- 结构图示
7.1 queue构造
queue<T> que
:默认构造。queue(const queue &que)
:拷贝构造。
7.2 queue赋值
queue& operator=(const queue &que)
7.3 queue数据存取
push(elem)
:队尾添加元素(入队)。pop()
:移除队头元素(出队)。back()
:返回队尾元素。front()
:返回队头元素。
7.4 queue大小操作
empty()
:判断队列是否为空。size()
:返回队列大小。- 使用示例
-
#include <iostream>#include <string>#include <queue>int main() {// 默认构造std::queue<int> que1;// 入队que1.push(10);que1.push(20);que1.push(30);que1.push(40);std::cout << "size: " << que1.size() << std::endl;while (!que1.empty()) {// 查看队头和队尾元素std::cout << "front: " << que1.front() << ", back: "<< que1.back() << std::endl;// 出队que1.pop();}std::cout << "size: " << que1.size() << std::endl;system("pause");return 0;}
-
- 打印结果
-
size: 4front: 10, back: 40front: 20, back: 40front: 30, back: 40front: 40, back: 40size: 0请按任意键继续. . .
-
8 list
- list是链表,一种物理存储单元上非连续的存储结构。list可以在任意位置进行快速插入和删除元素,但遍历速度没有vector快。list的迭代器属于双向迭代器。
- list插入和删除都不会造成原有list迭代器的失效。list的迭代器不支持随机访问。
- STL中的链表是一个双向循环链表。
- 结构图示
8.1 list构造
list<T> lst
:默认构造list(begin, end)
:将[begin, end)区间的元素拷贝给本身list(n, elem)
:将n个elem元素拷贝给本身list(const list &lst)
:拷贝构造。- 使用示例
-
#include <iostream>#include <string>#include <list>void printList(std::list<int>& lst) {std::cout << "list: ";for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {// 默认构造std::list<int> lst1;// 添加数据lst1.push_back(10);lst1.push_back(20);lst1.push_back(30);lst1.push_back(40);printList(lst1);// 区间方式构造std::list<int> lst2(lst1.begin(), lst1.end());printList(lst2);// 拷贝构造std::list<int> lst3(lst2);printList(lst3);std::list<int> lst4(5, 10);printList(lst4);system("pause");return 0;}
-
- 打印结果
-
list: 10 20 30 40list: 10 20 30 40list: 10 20 30 40list: 10 10 10 10 10请按任意键继续. . .
-
8.2 list赋值和交换
assign(beg, end)
:将[beg, end)区间的数据拷贝给本身。assign(n, elem)
:将n个elem元素拷贝给本身。list& operator=(const list &lst)
swap(lst)
:将lst元素与本身元素互换。- 使用示例
-
#include <iostream>#include <string>#include <list>void printList(std::list<int>& lst) {std::cout << "list: ";for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {// 默认构造std::list<int> lst1;// 添加数据lst1.push_back(10);lst1.push_back(20);lst1.push_back(30);lst1.push_back(40);printList(lst1);// 赋值std::list<int> lst2;lst2 = lst1;printList(lst2);std::list<int> lst3;lst3.assign(lst1.begin(), lst1.end());printList(lst3);std::list<int> lst4;lst4.assign(5, 10);printList(lst4);// 交换std::list<int> lst5;// 添加数据lst5.push_back(100);lst5.push_back(200);lst5.push_back(300);lst5.push_back(400);std::cout << "交换前" << std::endl;printList(lst1);printList(lst5);lst1.swap(lst5);std::cout << "交换前" << std::endl;printList(lst1);printList(lst5);system("pause");return 0;}
-
- 打印结果
-
list: 10 20 30 40list: 10 20 30 40list: 10 20 30 40list: 10 10 10 10 10交换前list: 10 20 30 40list: 100 200 300 400交换前list: 100 200 300 400list: 10 20 30 40请按任意键继续. . .
-
8.3 list容量和大小
empty()
:判断容器是否为空。size()
:返回容器中元素个数。resize(num)
:重新指定容器的长度为num。若容器变长,则以默认值填充新位置。若容器变短,则末尾超出容器长度的元素被删除。resize(num, elem)
:同上,重新指定容器长度为num,容器变长则以elem填充。
8.4 list插入和删除
push_back(elem)
:容器尾部插入一个元素elempop_back()
:删除容器中最后一个元素push_front(elem)
:在容器头部插入一个元素pop_front()
:移除容器头部的一个元素insert(pos, elem)
:在pos位置插入elem元素,返回新元素的位置insert(pos, n, elem)
:在pos位置插入n个elem元素,返回新元素的位置insert(pos, beg, end)
:在pos位置插入[beg, end)区间的元素,返回新元素的位置clear()
:移除容器中所有元素erese(beg, end)
:删除[beg, end)区间的元素,返回下一个元素的位置erese(pos)
:删除pos位置处的元素,返回下一个元素的位置remove(elem)
:删除容器中所有与elem值匹配的元素- 使用示例
-
#include <iostream>#include <string>#include <list>void printList(std::list<int>& lst) {std::cout << "list: ";for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {// 默认构造std::list<int> lst1;// 尾部添加数据lst1.push_back(10);lst1.push_back(20);lst1.push_back(30);lst1.push_back(40);// 头部添加元素lst1.push_front(50);lst1.push_front(60);printList(lst1);// 尾部删除lst1.pop_back();// 头部删除lst1.pop_front();printList(lst1);std::list<int>::iterator iter;// insert插入iter = lst1.begin();iter++;lst1.insert(iter, 1024);printList(lst1);// 删除iter = lst1.begin();lst1.erase(iter);printList(lst1);// 移除lst1.push_back(30);lst1.push_back(30);lst1.remove(30);printList(lst1);system("pause");return 0;}
-
- 打印结果
-
list: 60 50 10 20 30 40list: 50 10 20 30list: 50 1024 10 20 30list: 1024 10 20 30list: 1024 10 20请按任意键继续. . .
-
8.5 list数据存取
front()
:返回容器中第一个元素back()
:返回容器中最后一个元素
8.6 list反转和排序
reverse()
:反转链表sort()
:链表排序- 使用示例
-
#include <iostream>#include <string>#include <list>void printList(std::list<int>& lst) {std::cout << "list: ";for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}bool myCompare(int data1, int data2) {// 设置降序return data1 > data2;}int main() {// 默认构造std::list<int> lst1;// 尾部添加数据lst1.push_back(10);lst1.push_back(200);lst1.push_back(54);lst1.push_back(1024);lst1.push_back(521);printList(lst1);// 反转lst1.reverse();printList(lst1);// 排序 - 升序lst1.sort();printList(lst1);// 排序 - 降序lst1.sort(myCompare);printList(lst1);system("pause");return 0;}
-
- 打印结果
-
list: 10 200 54 1024 521list: 521 1024 54 200 10list: 10 54 200 521 1024list: 1024 521 200 54 10请按任意键继续. . .
-
9 pair对组
- pair是成对出现的数据,利用对组可以返回两个数据
9.1 创建方式
pair<type, type> p(value1, value2)
pair<type, type> p = make_pair(value1, value2)
- 使用示例
-
#include <iostream>#include <string>int main() {// 第一种创建方式std::pair<int, std::string> pa(10010, "Tom");std::cout << "pa.first: " << pa.first << ", pa.second: " << pa.second << std::endl;// 第二种创建方式std::pair<int, std::string> pa2 = std::make_pair(10020, "Mary");std::cout << "pa2.first: " << pa2.first << ", pa2.second: " << pa2.second << std::endl;system("pause");return 0;}
-
- 打印结果
-
pa.first: 10010, pa.second: Tompa2.first: 10020, pa2.second: Mary请按任意键继续. . .
-
10 set/multiset
- set/multiset属于关联式容器,底层结构是用二叉树实现(通常为平衡二叉树),所有元素会在插入时自动排序。
- set不允许容器中有重复的元素,multiset允许容器中有重复的元素。
- 结构图示
10.1 set构造和赋值
set<T> st
:默认构造set(const set& st)
:拷贝构造set& operator=(const set& st)
:赋值- 使用示例
-
#include <iostream>#include <string>#include <vector>#include <algorithm>#include <set>void printSet(std::set<int>& st) {// 遍历数据std::cout << "list: ";for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {std::set<int> st;// 插入数据st.insert(10);st.insert(100);st.insert(100);st.insert(15);st.insert(520);st.insert(2);printSet(st);// 拷贝构造std::set<int> st2(st);printSet(st2);// 赋值std::set<int> st3;st3 = st;printSet(st3);system("pause");return 0;}
-
- 打印结果
-
#include <iostream>#include <string>#include <vector>#include <algorithm>#include <set>void printSet(std::set<int>& st) {// 遍历数据std::cout << "list: ";for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {std::set<int> st;// 插入数据st.insert(10);st.insert(100);st.insert(100);st.insert(15);st.insert(520);st.insert(2);printSet(st);// 拷贝构造std::set<int> st2(st);printSet(st2);// 赋值std::set<int> st3;st3 = st;printSet(st3);system("pause");return 0;}
-
10.2 set大小和交换
size()
:获取容器中元素个数。empty()
:判断容器是否为空。swap(st)
:交换两个容器。
10.3 set插入和删除
insert(elem)
:插入元素。clear()
:清除所有元素。erase(pos)
:删除pos迭代器指向的元素,返回下一个元素的迭代器。erase(beg, end)
:删除区间[beg, end)的所有元素,返回下一个元素的迭代器。erase(elem)
:删除容器中值为elem的元素。
10.4 set查找和统计
find(key)
:查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end()。count(key)
:统计key的元素个数。对于set容器,只有0或者1。- 使用示例
-
#include <iostream>#include <string>#include <vector>#include <algorithm>#include <set>void printSet(std::set<int>& st) {// 遍历数据std::cout << "list: ";for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;}int main() {std::set<int> st;// 插入数据st.insert(10);st.insert(100);st.insert(100);st.insert(15);st.insert(520);st.insert(2);printSet(st);std::set<int>::iterator iter = st.find(100);if (iter != st.end()) {std::cout << "*iter: " << *iter << std::endl;}std::cout << "st.count(100): " << st.count(100) << std::endl;system("pause");return 0;}
-
- 打印结果
-
list: 2 10 15 100 520*iter: 100st.count(100): 1请按任意键继续. . .
-
10.5 set和multiset区别
- set不可以插入重复数据,而multiset可以。
- set插入数据的同时会返回插入结果,表示是否插入成功。multiset不会检测数据,因此可以插入重复数据。
- 示例
-
#include <iostream>#include <set>int main() {std::set<int> st;// 插入数据std::pair<std::set<int>::iterator, bool> ret;// 返回值为pair, 第一个参数为插入位置迭代器,第二个参数表示是否插入成功ret = st.insert(100);if (ret.second) {// 插入成功std::cout << "插入成功: " << *ret.first <<std::endl;}else {// 插入失败std::cout << "插入失败" << std::endl;}ret = st.insert(100);if (ret.second) {// 插入成功std::cout << "插入成功: " << *ret.first << std::endl;}else {// 插入失败std::cout << "插入失败" << std::endl;}std::multiset<int> mst;std::set<int>::iterator iter;// 返回值为插入位置迭代器iter = mst.insert(200);std::cout << "*iter: " << *iter << std::endl;iter = mst.insert(200);std::cout << "*iter: " << *iter << std::endl;system("pause");return 0;}
-
- 打印结果
-
插入成功: 100插入失败*iter: 200*iter: 200请按任意键继续. . .
-
10.6 set容器排序
- set容器默认排序规则是从小到大,利用仿函数,可以改变默认排序规则。
- set存放内置数据类型
- 使用示例
-
#include <iostream>#include <string>#include <vector>#include <algorithm>#include <set>// 利用仿函数指定排序规则为从大到小class myCompare {public:bool operator()(int data1, int data2) {return data1 > data2;}};int main() {std::set<int> st;// 插入数据st.insert(10);st.insert(100);st.insert(15);st.insert(520);st.insert(2);std::cout << "st: ";for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;// 指定排序规则为从大到小// 利用仿函数std::set<int, myCompare> st2;st2.insert(10);st2.insert(100);st2.insert(15);st2.insert(520);st2.insert(2);std::cout << "st2: ";for (std::set<int, myCompare>::iterator iter = st2.begin(); iter != st2.end(); iter++) {std::cout << *iter << " ";}std::cout << std::endl;system("pause");return 0;}
-
- 打印结果
-
st: 2 10 15 100 520st2: 520 100 15 10 2请按任意键继续. . .
-
- set存放自定义数据类型
- 使用示例
-
#include <iostream>#include <string>#include <set>class Person {public:Person(int code, std::string name) {mCode = code;mName = name;}int mCode;std::string mName;};// 利用仿函数指定排序规则class myComparePerson {public:bool operator()(const Person &p1, const Person &p2) {return p1.mCode < p2.mCode;}};int main() {std::set<Person, myComparePerson> st;Person p1(10010, "Tom");Person p2(10080, "Jack");Person p3(10000, "Mary");Person p4(11100, "Lucy");// 插入数据st.insert(p1);st.insert(p2);st.insert(p3);st.insert(p4);for (std::set<Person, myComparePerson>::iterator iter = st.begin(); iter != st.end(); iter++) {std::cout << iter->mCode << " " << iter->mName << std::endl;}system("pause");return 0;}
-
- 打印结果
-
10000 Mary10010 Tom10080 Jack11100 Lucy请按任意键继续. . .
-
11 map/multimap
- map中所有元素都是pair,pair中第一个元素为key(键值),起到索引作用,第二个元素为value(值),所有元素都会根据元素的键值自动排序。
- map/multimap属于关联式容器,底层结构是用二叉树实现(通常为平衡二叉树)。
- map中不允许容器中有重复key值,multimap允许容器中有重复key值。
- 结构图示
11.1 map构造和赋值
map<T1, T2> mp
:默认构造map(const map &mp)
:拷贝构造map& operator=(const map& mp)
:等号赋值。- 使用示例
-
#include <iostream>#include <string>#include <map>void printMap(std::map<int, std::string>& mp) {// 遍历数据for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;}}int main() {std::map<int, std::string> mp;// 插入数据mp.insert(std::pair<int, std::string>(10010, "AA"));mp.insert(std::pair<int, std::string>(11000, "BB"));mp.insert(std::pair<int, std::string>(11110, "CC"));mp.insert(std::pair<int, std::string>(10000, "DD"));mp.insert(std::pair<int, std::string>(10001, "EE"));std::cout << "mp: " << std::endl;printMap(mp);// 拷贝构造std::map<int, std::string> mp2(mp);std::cout << "mp2: " << std::endl;printMap(mp2);// 赋值std::map<int, std::string> mp3;mp3 = mp;std::cout << "mp3: " << std::endl;printMap(mp3);system("pause");return 0;}
-
- 打印结果
-
mp:iter->first: 10000, iter->second: DDiter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CCmp2:iter->first: 10000, iter->second: DDiter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CCmp3:iter->first: 10000, iter->second: DDiter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CC请按任意键继续. . .
-
11.2 map大小和交换
size()
:返回容器中元素个数。empty()
:判断容器是否为空。swap(st)
:交换两个容器数据。
11.3 map插入和删除
insert(elem)
:插入元素。clear()
:清除所有元素。erase(pos)
:删除pos迭代器指向的元素,返回下一个元素的迭代器。erase(beg, end)
:删除区间[beg, end)的所有元素,返回下一个元素的迭代器。erase(elem)
:删除容器中值为elem的元素。- 使用示例
-
#include <iostream>#include <string>#include <map>void printMap(std::map<int, std::string>& mp) {// 遍历数据for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;}}int main() {std::map<int, std::string> mp;// 插入数据// 第一种插入方式mp.insert(std::pair<int, std::string>(10010, "AA"));mp.insert(std::pair<int, std::string>(11000, "BB"));// 第二种插入方式mp.insert(std::make_pair(11110, "CC"));mp.insert(std::make_pair(10000, "DD"));// 第三种插入方式mp.insert(std::map<int, std::string>::value_type(10001, "EE"));// 第四种插入方式(不建议使用)mp[11111] = "FF";std::cout << "mp: " << std::endl;printMap(mp);// 删除// 根据迭代器删除mp.erase(mp.begin());std::cout << "根据迭代器删除: " << std::endl;printMap(mp);// 根据key值删除mp.erase(11111);std::cout << "根据key值删除: " << std::endl;printMap(mp);system("pause");return 0;}
-
- 打印结果
-
mp:iter->first: 10000, iter->second: DDiter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CCiter->first: 11111, iter->second: FF根据迭代器删除:iter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CCiter->first: 11111, iter->second: FF根据key值删除:iter->first: 10001, iter->second: EEiter->first: 10010, iter->second: AAiter->first: 11000, iter->second: BBiter->first: 11110, iter->second: CC请按任意键继续. . .
-
11.4 map查找和统计
find(key)
:查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回map.end()。count(key)
:统计key的元素个数。对于map容器,只有0或者1。- 使用示例
-
#include <iostream>#include <string>#include <map>void printMap(std::map<int, std::string>& mp) {// 遍历数据for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;}}int main() {std::map<int, std::string> mp;// 插入数据mp.insert(std::pair<int, std::string>(10010, "AA"));mp.insert(std::pair<int, std::string>(11000, "BB"));mp.insert(std::pair<int, std::string>(11110, "CC"));mp.insert(std::pair<int, std::string>(10000, "DD"));mp.insert(std::pair<int, std::string>(10001, "EE"));// 查找std::map<int, std::string>::iterator iter = mp.find(11110);if (iter != mp.end()) {std::cout << "找到了" << std::endl;std::cout << "key: " << iter->first << ", value: " << iter->second << std::endl;}else {std::cout << "未找到" << std::endl;}// 统计std::cout << "mp.count(10000): " << mp.count(10000) <<std::endl;system("pause");return 0;}
-
- 打印结果
-
找到了key: 11110, value: CCmp.count(10000): 1请按任意键继续. . .
-
11.5 map容器排序
- map容器默认排序规则是从小到大,利用仿函数,可以改变默认排序规则。
- 使用示例
-
#include <iostream>#include <string>#include <map>class myCompare {public:bool operator()(int data1, int data2) {return data1 > data2;}};int main() {std::map<int, std::string, myCompare> mp;// 插入数据mp.insert(std::pair<int, std::string>(10010, "AA"));mp.insert(std::pair<int, std::string>(11000, "BB"));mp.insert(std::pair<int, std::string>(11110, "CC"));mp.insert(std::pair<int, std::string>(10000, "DD"));mp.insert(std::pair<int, std::string>(10001, "EE"));for (std::map<int, std::string, myCompare>::iterator iter = mp.begin(); iter != mp.end(); iter++) {std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;}system("pause");return 0;}
-
- 打印结果
-
iter->first: 11110, iter->second: CCiter->first: 11000, iter->second: BBiter->first: 10010, iter->second: AAiter->first: 10001, iter->second: EEiter->first: 10000, iter->second: DD请按任意键继续. . .
-
相关文章:
C++ STL之容器介绍(vector、list、set、map)
1 STL基本概念 C有两大思想,面向对象和泛型编程。泛型编程指编写代码时不必指定具体的数据类型,而是使用模板来代替实际类型,这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C泛型编程的一个杰出例子。STL(Standard …...
【向量数据库 Milvus】Milvus 2.5版本CPU 安装单机版
以下是Milvus 2.5版本单机安装的步骤: 前提条件 系统可以使用centos或者ubuntu。系统已经安装docker和docker-compose。 下载并编辑docker-compose.yml 进入Milvus的GitHub项目主页查看最新版本的Milvus,下载对应版本的docker-compose.yml文件&#…...
[Do374]Ansible一键搭建sftp实现用户批量增删
[Do374]Ansible一键搭建sftp实现用户批量增删 1. 前言2. 思路3. sftp搭建及用户批量新增3.1 配置文件内容3.2 执行测试3.3 登录测试3.4 确认sftp服务器配置文件 4. 测试删除用户 1. 前言 最近准备搞一下RHCA LV V,外加2.9之后的ansible有较大变化于是练习下Do374的课程内容. 工…...
系统认识数据分析
什么是数据分析? 数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,将它们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。数据分析是为了提取有用信息和形成结论而对数据加以详细研究和概括总结的…...
Cherno C++学习笔记 P52 处理多返回值
在这篇文章当中,我们解决一下如何用C的函数处理多返回值的问题。 在有些情况下,我们希望我们的函数可以返回多个返回值,比如返回两个string或者是一个int加上一个string。如果我们用的是python之类的语言的话,那这个事情其实是很…...
Android车机DIY开发之学习篇(一)编译UBOOT以正点原子为例
Android车机DIY开发之学习篇(一)编译UBOOT以正点原子为例 1.代码在u-boot文件夹下 2.在 U-Boot 源码目录下执行如下命令编译 U-Boot: ./make.sh rk3588生成两个文件 ### uboot.img 对应<SDK>/uboot/uboot.img ### rk3588_spl_loader_v1.13.113.bin 对应<…...
扩散模型、原型网络以及肿瘤微环境解析等名词出现在基金立项名单中,它们各自的应用现状如何?|文献速递·25-01-10
小罗碎碎念 昨晚看到了云南省2025年自然科学基金立项的名单,今天把医工交叉的项目挑出来和大家分享一下。 今天分享的文献,灵感来源于2025年的基金,我会先简单分析一下基金的情况,然后再和大家分享三篇与立项基金相关的文献。 总共…...
【Java设计模式-4】策略模式,消灭if/else迷宫的利器
各位Java编程小伙伴们!今天咱们要一起探索一个超级厉害的Java设计模式——策略模式,它就像是一把神奇的魔法剑,专门用来斩断那些让我们代码变得乱糟糟的if/else语句迷宫! 一、if/else的烦恼 在编程的奇妙世界里,我们…...
10分钟快速了解OceanGPT(沧渊)
10分钟快速了解OceanGPT(沧渊) 海洋科学任务的大语言模型——OceanGPT OceanGPT是如何训练的?为了训练 OceanGPT (沧渊) ,收集了一个跨越多个领域的海洋科学语料库。由于每个子领域和主题都有其独特的数据特征和模式,因此提出了一个特定于领域的指令生成框架,称为 DoDirec…...
学习及笔记
1、计算md5 md5sum 文件名 2、跨服务器复制 scp 文件 目标用户名目标Ip:目标路径 3、curl curl -X POST http://10.105.2.46/getUerls -H "Content-Type: application/json" -d {"id": 379, "userId": "lyc", "password":…...
TensorFlow Quantum快速编程(基本篇)
一、TensorFlow Quantum 概述 1.1 简介 TensorFlow Quantum(TFQ)是由 Google 开发的一款具有开创性意义的开源库,它宛如一座桥梁,巧妙地将量子计算与 TensorFlow 强大的机器学习功能紧密融合。在当今科技飞速发展的时代,传统机器学习虽已取得诸多瞩目成就,然而面对日益…...
Vue.js组件开发-实现图片裁剪
在Vue.js中开发一个图片裁剪组件,可以使用cropperjs库,它是一个功能强大的JavaScript库,专门用于图片裁剪。在Vue项目中,可以通过vue-cropperjs这个Vue包装器来更方便地使用cropperjs。 步骤: 1. 安装依赖 首先&…...
Jira用例自动去除summary重复用例
title: Jira用例自动去除summary重复用例 tags: - jira - python categories: - python一、背景与需求二、解决方案思路三、实施步骤本文永久更新地址: 在使用 Jira 进行项目管理时,测试用例的维护至关重要。随着项目推进,用例数量增多,可能…...
2024年开发语言热度排名
随着技术的不断发展和变化,编程语言的热度也在不断演变。2024年即将到来,我们有必要回顾和展望当前和未来的开发语言市场。本文将基于多个因素,包括行业需求、社区支持、流行度以及新兴趋势,对2024年的开发语言热度进行排名和分析…...
【ArcGIS初学】产生随机点计算混淆矩阵
混淆矩阵:用于比较分类结果和地表真实信息 总体精度(overall accuracy) :指对角线上所有样本的像元数(正确分类的像元数)除以所有像元数。 生产者精度(producers accuracy) :某类中正确分类的像元数除以参考数据中该类的像元数(列方向),又称…...
OpenScholar助高效检索和整合科学文献?
从事科研的人都离不开读文献。然而,如今每年发表的论文数量已达数百万篇(例如,某位大佬在硕博期间就发表了178篇~)。在如此海量的文献中,如何高效利用宝贵的时间获取所需信息,显得尤为重要。 近…...
代码随想录Day34 | 62.不同路径,63.不同路径II,343.整数拆分,96.不同的二叉搜索树
代码随想录Day34 | 62.不同路径,63.不同路径II,343.整数拆分,96.不同的二叉搜索树 62.不同路径 动态规划第二集: 比较标准简单的一道动态规划,状态转移方程容易想到 难点在于空间复杂度的优化,详见代码 class Solution {public int uniq…...
非PHP开源内容管理系统(CMS)一览
在现代网站开发中,内容管理系统(CMS)是不可或缺的工具。虽然许多广泛使用的CMS(如WordPress和Joomla)是基于PHP开发的,但其他编程语言同样诞生了许多优秀的开源CMS,适用于不同需求和技术栈的项目…...
【Rust】常见集合
目录 思维导图 一、Rust常用集合 1. Rust标准库中的集合概述 2. 常用集合类型 2.1 向量(Vector) 2.2 字符串(String) 2.3 哈希映射(Hash Map) 二、向量(Vec) 1. 向量的概述…...
55. 跳跃游戏
题目 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 C #include <…...
关于 ThinkPHP 与 PostgreSQL 结合使用的一些要点
ThinkPHP 是一款流行的 PHP 开发框架,而 PostgreSQL 是功能强大的开源关系型数据库。它们可以结合使用来开发各类应用,以下是关于 ThinkPHP 与 PostgreSQL 结合使用的一些要点: 配置数据库连接 编辑配置文件:在 ThinkPHP 项目中&…...
【 PID 算法 】PID 算法基础
一、简介 PID即:Proportional(比例)、Integral(积分)、Differential(微分)的缩写。也就是说,PID算法是结合这三种环节在一起的。粘一下百度百科中的东西吧。 顾名思义,…...
介绍下不同语言的异常处理机制
Golang 在Go语言中,有两种用于处于异常的机制,分别是error和panic; panic panic 是 Go 中处理异常情况的机制,用于表示程序遇到了无法恢复的错误,需要终止执行。 使用场景 程序出现严重的不符合预期的问题&#x…...
Sprint Boot教程之五十八:动态启动/停止 Kafka 监听器
Spring Boot – 动态启动/停止 Kafka 监听器 当 Spring Boot 应用程序启动时,Kafka Listener 的默认行为是开始监听某个主题。但是,有些情况下我们不想在应用程序启动后立即启动它。 要动态启动或停止 Kafka Listener,我们需要三种主要方法…...
Linux服务器网络丢包场景及解决办法
一、Linux网络丢包概述 在数字化浪潮席卷的当下,网络已然成为我们生活、工作与娱乐不可或缺的基础设施,如同空气般,无孔不入地渗透到各个角落。对于 Linux 系统的用户而言,网络丢包问题却宛如挥之不去的 “噩梦”,频繁…...
2025年01月13日Github流行趋势
1. 项目名称:Jobs_Applier_AI_Agent 项目地址url:https://github.com/feder-cr/Jobs_Applier_AI_Agent项目语言:Python历史star数:25929今日star数:401项目维护者:surapuramakhil, feder-cr, cjbbb, sarob…...
贪心算法详细讲解(沉淀中)
文章目录 1. 什么是贪心算法?(贪婪鼠目寸光)经典例题1.1.1 找零问题1.1.2最小路径和1.1.3 背包问题 2.贪心算法的特点2.1 证明例1 3.学习贪心的方向心得体会 1. 什么是贪心算法?(贪婪鼠目寸光) 贪心策略&a…...
C/C++ 数据结构与算法【排序】 常见7大排序详细解析【日常学习,考研必备】带图+详细代码
常见7种排序算法 冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort)希尔排序(Shell Sort)归并排序(Merge Sort)快速排序(…...
Oracle Dataguard(主库为双节点集群)配置详解(4):配置备库
Oracle Dataguard(主库为双节点集群)配置详解(4):配置备库 目录 Oracle Dataguard(主库为双节点集群)配置详解(4):配置备库一、为备库配置静态监听1、配置 li…...
【Unity3D日常开发】Unity3D中打开Window文件对话框打开文件(PC版)
推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群:398291828小红书小破站 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 这篇文章继续讲如何使用Unity3D打开Window文…...
STM32-RTC实时时钟
1.0 RTC简介 RTC(Real Time Clock)实时时钟 RTC是一个独立的定时器,可为系统提供时钟和日历的功能 RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD(2.0~3.6V)断电后可借助VBAT&#x…...
QT跨平台应用程序开发框架(1)—— 环境搭建
目录 一,关于QT 二,关于应用程序框架 三,环境搭建 3.1 预备 3.2 下载Qt SDK 3.3 安装Qt SDK 3.4 配置环境变量 3.5 认识一些重要工具 四,Qt Creator 的基本使用 4.1 创建项目 4.2 代码解释 一,关于QT 互联网…...
HTB:Paper[WriteUP]
目录 连接至HTB服务器并启动靶机 信息收集 使用rustscan对靶机TCP端口进行开放扫描 将靶机TCP开放端口号提取并保存 使用nmap对靶机TCP开放端口进行脚本、服务扫描 使用nmap对靶机TCP开放端口进行漏洞、系统扫描 使用nmap对靶机常用UDP端口进行开放扫描 对靶机进行子域…...
【数据可视化-12】数据分析岗位招聘分析
🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...
UE材质节点Fresnel
Fresnel节点 ExponentIn 控制边缘透明度 BaseReflectFractionIn 控制中心透明度...
宁德时代C++后端开发面试题及参考答案
请阐述面向对象的三大特性。 面向对象编程有三大特性,分别是封装、继承和多态。 封装是指将数据和操作数据的方法绑定在一起,对数据的访问和操作进行限制。这样做的好处是可以隐藏对象的内部细节,只暴露必要的接口给外部。例如,我们可以把一个汽车类的内部引擎状态、速度等…...
opencv warpAffine仿射变换C++源码分析
基于opencv 3.1.0源代码 sources\modules\imgproc\src\imgwarp.cpp void cv::warpAffine( InputArray _src, OutputArray _dst,InputArray _M0, Size dsize,int flags, int borderType, const Scalar& borderValue ) {...if( !(flags & WARP_INVERSE_MAP) ){//变换矩阵…...
六十九:基于openssl实战验证RSA
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,广泛应用于数据加密和数字签名领域。在实际开发和学习过程中,理解 RSA 的工作原理和使用场景非常重要。本文将以 OpenSSL 工具为基础,通过实例操作来验证和理解 RSA 的…...
Docker的CMD指令
CMD指令是Dockerfile中的一个重要指令,用于指定容器启动时执行的默认命令。CMD为容器运行时提供了一个默认的执行指令,可以在容器启动时自动运行该命令。 * CMD指令用于指定容器启动时的默认命令 CMD指令指定的命令通常是容器启动后要执行的主要进程。…...
redis缓存篇知识点总结
1.缓存雪崩 当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃 发生缓存雪崩有两…...
onlyoffice编辑服务部署
下载官方镜像 下载onlyoffice_7.4.1.tar.gz镜像包 安装官方镜像 上传镜像包后执行 docker load -i onlyoffice_7.4.1.tar.gz 将镜像部署到本地仓库 下载onlyoffice编辑服务包 下载onlyoffice.zip包 启动onlyoffice编辑服务 上传包至服务器,解压包,…...
RPC实现原理,怎么跟调用本地一样
回答1 要让⽹络通信细节对使⽤者透明,我们需要对通信细节进⾏封装,我们先看下⼀个 RPC 调⽤的流程涉及到哪些通 信细节: 1. 服务消费⽅( client )调⽤以本地调⽤⽅式调⽤服务; 2. client stub 接收到调…...
JDK下载安装配置
一.JDK安装配置。 1.安装注意路径,其他直接下一步。 2.配置。 下接第4步. 或者 代码复制: JAVA_HOME D:\Program Files\Java\jdk1.8.0_91 %JAVA_HOME%\bin 或者直接配置 D:\Program Files\Java\jdk1.8.0_91\bin 3.验证(CMD)。 java javac java -version javac -version 二.下…...
C++(3)
1.顺序表封装 #include <iostream>using namespace std;//类型重命名 using datatype int;//定义一个顺序表类 class SeqList { private:datatype *data;//指向堆区空间的指针int size 0;//数组大小int len 0;//顺序表实际长度public://无参构造SeqList():data(new d…...
工具学习_Conan_Install
1. 依赖关系获取 为了获取TPL间的依赖关系,我们首先从 GitHub 项目中提取 Conan 包含的组件,如下所示: 在获取组件名之后,我们根据组件名从 Conan 中获取 TPL 间的依赖关系,如下图所示: 之后获得包含TPL间…...
忘记了PDF文件的密码,怎么办?
PDF文件可以加密,大家都不陌生,并且大家应该也都知道PDF文件有两种密码,一个打开密码、一个限制编辑密码,因为PDF文件设置了密码,那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密? PDF和offi…...
HTML实战课堂之启动动画弹窗
一:代码片段讲解 小提示:下面是一个包含启动页和弹窗的完整示例。这个示例包括一个简单的启动页和一个弹窗,当用户点击启动页上的按钮时,会显示弹窗。 1. **HTML结构**: - #startPage:启动页,包…...
thinkphp 5.0 结合redis 做延迟队列,队列无法被消费
目录 一、Linux 环境下 二、如何验证消息队列被正确监听 一、Linux 环境下 项目部署在Linux 环境下,首先找到项目的部署路径,接着输入命令,这个命令是以守护进程方式进行监听你的队列,只要redis 不关闭 就可以一直监听这个队列 nohup php …...
open3d+opencv实现矩形框裁剪点云操作(C++)
👑主页:吾名招财 👓简介:工科学硕,研究方向机器视觉,爱好较广泛… 💫签名:面朝大海,春暖花开! open3dopencv实现矩形框裁剪点云操作(Cÿ…...
Android RIL(Radio Interface Layer)全面概述和知识要点(3万字长文)
在Android面试时,懂得越多越深android framework的知识,越为自己加分。 目录 第一章:RIL 概述 1.1 RIL 的定义与作用 1.2 RIL 的发展历程 1.3 RIL 与 Android 系统的关系 第二章:RIL 的架构与工作原理 2.1 RIL 的架构组成 2.2 RIL 的工作原理 2.3 RIL 的接口与协议…...