网站建设联雅/珠海网站seo
✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:C/C++知识点
📣专栏定位:整理一下 C++ 相关的知识点,供大家学习参考~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
🎏唠叨唠叨:在这个专栏里我会整理一些琐碎的 C++ 知识点,方便大家作为字典查询~
STL
概述
STL,学名Standard Template Library,一般称它为标准模板库。
C++ 对模板(Template)支持得很好,STL 就是借助模板把常用的数据结构及其算法都实现了一遍,并且做到了数据结构和算法的分离。例如,vector 的底层为顺序表(数组),list 的底层为双向链表,deque 的底层为循环队列,set 的底层为红黑树,hash_set 的底层为哈希表。
从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map一大堆,STL也是算法和其他一些组件的集合。比如说中sort函数。
STL基本组成
STL从广义上讲分为三类:
- 容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
- 迭代器(Iterator),提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符地方法的类对象;
- 算法(Algorithm),是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
string容器
用字符数组存放字符串容易发生数组越界的错误,而且往往难以察觉。因此,C++ 标准模板库设计了string 数据类型,专门用于字符串处理。
要使用string 对象,须包含头文件。
在用C++ 编程时,要优先考虑用string 对象来处理字符串,因为其用法比字符数组更简单,而且不容易出错。
初始化
string对象的初始化和普通类型变量的初始化基本相同,只是string作为类,还有类的一些特性:使用构造函数初始化。
string s1; //默认初始化,一个空字符串s1
string s2(s1); //s2是s1的副本
string s3 = s1; //等价于s3(s1),s3是s1的副本
string s4(“hello”); //s4是字面值”hello”
string s5 = “hello”; //等价于上行代码
string s6(n,’a’); //把s6初始化为由连续的n个字符c组成的串
//调用string的构造函数生成一个临时的string类,再用临时的string类初始化。
string s7 = string(“hello”);
string s8(string(“hello”));
输入输出
- cin 输入
string s1;
cin >> s1; //遇到空格终止
cout << s1 << endl;
- getline读取整行
string s1;
getline(cin,s1);
cout << s1 << endl;
vs里面使用getline,须加上#include
比较大小
string可以直接使用> ,< == 等进行比较。
string s1 = “abc”,s2=”eda”;
s1 > s2
s1 < s2
s1 == s2
链接
string可以使用+来直接链接。
string s1 = “hello”,s2 = “ world”;
string s3 = s1 + s2;
获取字符
- 使用C++11新特性的for
string s1 = “abcdefg”;
for (auto c:s1){cout << c << “ “;
}
- 使用运算符[] + size()函数
s1[0];
s1[1];
s1[2];
- 使用迭代器
string s1 = “hello world”;
for(auto i=s1.begin();i!=s1.end();i++){cout << *i << “ “;
}
拷贝string对象
第一个将s1从下标pos开始拷贝到结尾。当pos>s1.size()时,为未定义行为;当pos=s1.size(),拷贝一个空字符。
第二个将s1从下标pos开始拷贝,拷贝len个字符。当pos>s1.size()时,为未定义行为;当pos=s2.size(),拷贝一个空字符。
string s(s1,pos);
string s(s1,pos,len);
案例:
string s1("hello");
(1) string s2(s1, 1);//s2为”ello”,长度为4
(2) string s3(s1, 5);//s3为””,长度为0
(3) string s8(s1, 6);// 错误,未定义的行为,抛出异常
(4) string s4(s1, 1, 3);// s4为”ell”,长度为3
(5) string s5(s1, 1, 8);// 正确,s5为”ello”,长度为4
(6) string s6(s1, 5, 8);// s6为””,长度为0
(7) string s7(s1, 6, 1);// 错误,未定义的行为,抛出异常
substr函数
返回一个string对象,返回的对象包含s从pos下标开始的n个字符。pos和n均为可选参数。pos默认为下标0;n默认为s.size()-pos。
s.substr(pos,n);
案例:
string s ("value");
(1)string s2 = s.substr();//s2为”value”,大小为5
(2)string s3 = s.substr(2);//s3为”lue”,大小为3
(3)string s4 = s.substr(5);//s3为””,大小为0
(4)string s5 = s.substr(6);//错误,s5的大小为pos = 5,小于s.size()
(5)string s6 = s.substr(1,2);// s6为”al”,大小为2
(6)string s7 = s.substr(1,7);// s7为”alue”,大小为4
(7)string s8 = s.substr(5,7);// s8为””,大小为0
(8)string s9 = s.substr(6,7);// 错误,s9的大小为pos = 5,小于s.size()
insert函数
- iterator insert( iterator pos, CharT ch )
- void insert( iterator pos, size_type count, CharT ch )
- void insert( iterator pos, InputIt first, InputIt last )
- 插入初始化列表
案例:
string s1("value");
s1.insert(s1.begin(), 's');//执行后,s1为"svalue"
s1.insert(s1.begin(), 1, 's');//执行后,s1为"ssvalue"
s1.insert(s1.begin(), s1.begin(), ++s1.begin());//执行后,s1为"sssvalue"
s1.insert(s1.end(), {'1','2'});//执行后,s1为"sssvalue12"
erase函数
//删除s从pos下标开始的n个字符,并返回删除后的s。当pos > s.size()时,报错
basic_string & erase(size_type pos=0, size_type n=npos);//删除s迭代器position位置的字符,并返回下一个字符的迭代器。
iterator erase(const_iterator position);//删除s迭代器[first,last)区间的字符,并返回last字符的迭代器。
iterator erase(const_iterator first, const_iterator last);
案例:
string s1("value");
string s2("value");
string s3("value");
string s4("value");
s1.erase();//执行后,s1为空
s2.erase(0,2); //执行后,s2为”lue”
s2.erase(1); //执行后,s2为"l"
s3.erase(s3.begin());//执行后,s3为”alue”
s4.erase(s4.begin(),++s4.begin());//执行后,s4为”alue”
append函数
append是在string对象的末尾进行插入操作,这一点使用+运算符也能做到。
案例:
string s="C++";
s.append("program");//执行完后,s=”C++program”
replace函数
案例:
string s("i very love China!");const char* cp1 = "truly";
const char* cp2 = "truly!!!";string str1 = "really";
string str2 = "really!!!";//1.将s从下标2开始删除4个字符,删除后在下标2处插入cp1
s.replace(2,4,cp1);//s=” i truly love China!”
//2.将s从下标2开始删除5个字符,删除后在下标2插入cp2的前5个字符
s.replace(2, 5, cp2,5); //s=” i truly love China!”
//3.将s从下标2开始删除5个字符,删除后在下标2插入str1
s.replace(2, 5, str1);//s=”i really love China!”
//4.将s从下标2开始删除6个字符,删除后在下标2插入str2从下标0开始的6个字符
s.replace(2, 6, str2, 0, 6);//s=”i really love China!”
//5.将s从下标2开始删除6个字符,删除后在下标2插入4个’*’字符
s.replace(2, 6, 4, '*');//s=”i **** love China!”
其他函数
- find( )函数
string s = "1230,3210,220";
int start = 0;
int index = s.find(',', start); //从下标为0开始查找,返回第一个','的下标,如果找不到返回-1
- ispunct()函数:判断字符是否是标点符号用ispunct()
string s;
cin >> s;
for (auto each : s) {if (!ispunct(each)) {cout << each;}
}
vector容器
c++ 中,vector 是一个十分有用的容器。它能够像容器一样存放各种类型的对象。也就是说,vector是一个能够存放任意类型的动态数组。
vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string 对象一样,标准库将负责管理与存储元素相关的内存。
把vector 称为容器,是因为它可以包含其他对象。一个容器中的所有对象都必须是同一种类型的。
头文件
使用vector须包含头文件vector
#include <vector>
声明与初始化
vector 可以声明各种类型,整型、字符型、字符串等等!
//整形数组
vector <int> vec = { 1,2,3,4,5};
//char型数组
vector <char> vec1 = {'h','e','l' ,'l' ,'o' };
//double
vector<double> vec2 = {1.1,2.2,3.3};
利用构造函数初始化
vector():创建一个空vector vector(int nSize):创建一个vector,元素个数为nSize
vector(int nSize,const t& t):创建一个vector,元素个数为nSize,且值均为t
vector(const vector&):复制构造函数
vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
案例:
vector <int> vec(10);//定义一个含10个变量的整型数组vec,默认值都为0
vector <int> vec(10,2);//定义一个含10个变量的整型数组vec,默认值都为2
vector<int> vec(a);//其中a也是vector,把a整体赋值给vec
vector<int> vec(a.begin(),a.begin+1);//把a的从开始到第二个赋值给vec
遍历函数
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
案例:
vector<int> v = { 1,2,3,4,5,6 };
cout << v.at(1) << endl; // 打印2
cout << v.front() << endl; //打印1
cout << v.back() << endl; // 打印6
for (auto i = v.begin(); i != v.end(); i++) {cout << *i << " ";
}
//输出1 2 3 4 5 6
cout << endl;
for (auto i = v.rbegin(); i != v.rend(); i++) {cout << *i << " ";
}
//输出6 5 4 3 2 1
添加函数
//向量尾部增加一个元素X
void push_back(const T& x);//向量中迭代器指向元素前增加一个元素x
iterator insert(iteratorit,const T& x);//向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,int n,const T& x);//向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据
iterator insert(iterator it,const_iterator first,const_iterator last);
案例:
vector<int> v = { 1,2 };
vector<int> v2 = { 100,200 };
v.push_back(3);
v.insert(v.begin(), 11);
v.insert(v.begin() + 1, 3, 22);
v.insert(v.begin(), v2.begin(), v2.end());
for (auto i = v.begin(); i != v.end(); i++) {cout << *i << " ";
}
//输出100 200 11 22 22 22 1 2 3
删除函数
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
案例:
vector<int> v = { 1,2,3,4,5,6 };
v.erase(v.begin()+1);//删除2
v.erase(v.begin() + 2, v.begin() + 4); //删除4 ,5
v.pop_back(); //删除最后一个元素
v.clear(); //清空所有元素
for (auto i = v.begin(); i != v.end(); i++) {cout << *i << " ";
}
判断函数
bool empty() const:判断向量是否为空,若为空,则向量中无元素,返回1;反之,返回0
cout << v.empty() << endl;
大小函数
int size() const:返回向量中元素的个数
int capacity() const:返回当前向量所能容纳的最大元素值
int max_size() const:返回最大可允许的vector 元素数量值
案例:
vector<int> v = { 1,2,3,4,5,6 };
cout << v.size() << endl; //输出6
cout << v.capacity() << endl; //输出6
cout << v.max_size() << endl; //输出4611686018427387903
其他函数
- void swap(vector&):交换两个同类型向量的数据
- void assign(int n,const T& x):设置向量中前n个元素的值为x
- void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素
stack容器
stack(栈)容器是一种先进后出的容器,两端只有一个开口,只能从这一个开口插入和删除数据。
头文件
使用时包含头文件stack
#include<stack>
构造函数
stack<T> stkT;//stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk);//拷贝构造函数
赋值函数
stack&operator=(const stack &stk);//重载等号操作符
数据存取
push(elem);//向栈顶添加元素
pop();//从栈顶移除第一个元素
top();//返回栈顶元素
大小函数
empty();//判断堆栈是否为空
size();//返回堆栈的大小
queue容器
Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口。
- 队列容器允许从一端新增元素,从另一端移除元素
- 队列中只有对头和队尾才可以被外界使用,因此队列不允许有遍历的行为
- 队列中进数据称为–入队push
- 队列中出数据称为–出队pop
头文件
queue模版类的定义在头文件中。
#include<queue>
构造函数
queue<T> queT;//queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que);//拷贝构造函数
//案例
queue<int> q1;
queue<int> q2(q1);
相关函数
push(elem);//往队尾添加元素
pop();//从队头移除第一个元素
back();//返回最后一个元素
front();//返回第一个元素
empty();//判断队列是否为空
size();//返回队列的大小
deque容器
deque双端队列,可以对头端和尾端进行插入删除操作。
deque队列为一个给定类型的元素进行线性处理,像向量一样,它能够快速地随机访问任一个元素,并且能够高效地插入和删除容器的尾部元素。但它又与vector不同,deque支持高效插入和删除容器的头部元素。
构造函数
deque<T> deqT; //默认构造形式
deque(beg, end); //构造函数将[beg,end]区间中的元素拷贝给本身
deque(n, elem); //构造函数将n个elem拷贝给本身
deque(const deque &deq); //拷贝构造函数
案例:
deque<int> a; // 定义一个int类型的双端队列a
deque<int> a(10); //定义一个int类型的双端队列a,并设置初始大小为10
deque<int> a(10, 1); //定义一个int类型的双端队列a,并设置初始大小为10且初始值都为1
deque<int> b(a); //定义并用双端队列a初始化双端队列b
deque<int> b(a.begin(), a.begin()+3); //将双端队列a中从第0个到第2个(共3个)作为双端队列b的初始值
添加函数
d.push_front(const T& x);//头部添加元素
d.push_back(const T& x);//末尾添加元素
d.insert(iterator it, const T& x);//任意位置插入一个元素
d.insert(iterator it, int n, const T& x);//任意位置插入n 个相同元素
d.insert(iterator it, iterator first, iterator last);//插入另一个向量的[forst,last] 间的数据
案例:
#include <iostream>
#include <deque>
using namespace std;
int main(){deque<int> d1;//头部增加元素d1.push_front(4);//末尾添加元素d1.push_back(5);//任意位置插入一个元素deque<int>::iterator it = d1.begin();d1.insert(it, 2);//任意位置插入n个相同元素it = d1.begin(); d1.insert(it, 3, 9);//插入另一个向量的[forst,last]间的数据deque<int> d2(5, 8);it = d1.begin(); d1.insert(it, d2.end() -1, d2.end());//遍历显示for (it = d1.begin(); it != d1.end(); it++)cout << *it << " "; // 输出:8 9 9 9 2 4 5cout << endl;return 0;
}
删除函数
d1.pop_front();//头部删除元素
d1.pop_back();//末尾删除元素
d1.erase(iterator it);//任意位置删除一个元素
d1.erase(iterator first, iterator last);//删除[first,last] 之间的元素
d1.clear();//清空所有元素:
访问函数
下标访问:deq[1]; // 并不会检查是否越界
at 方法访问:deq.at(1); // 以上两者的区别就是 at 会检查是否越界,是则抛出 out of range 异常
访问第一个元素:deq.front();
访问最后一个元素:deq.back();
大小函数
d.size();//容器大小
d.max_size();//容器最大容量
d.resize();//更改容器大小
deq.empty();//容器判空
deq.shrink_to_fit();//减少容器大小到满足元素所占存储空间的大小
其他函数
deq.assign(int nSize, const T& x); //多个元素赋值
// 类似于初始化时用数组进行赋值swap(deque&);//交换两个同类型容器的元素
案例:
#include <iostream>
#include <deque>
using namespace std;
int main(){// 多个元素赋值deque<int> d1;d1.assign(3, 1);deque<int> d2;d2.assign(3, 2);// 交换两个容器的元素d1.swap(d2);// 遍历显示cout << "d1: ";for (int i = 0; i < d1.size(); i++)cout << d1[i] << " "; // 输出:2 2 2cout << endl;// 遍历显示cout << "d2: ";for (int i = 0; i < d2.size(); i++)cout << d2[i] << " "; // 输出:1 1 1cout << endl;return 0;
}
list容器
list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是list也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的。
头文件
#include<list>
初始化
list<int> l1; //创建一个空链表
list<int> l2(10); //创建一个链表其有10个空元素
list<int> l3(5,20); //创建一个链表其有5个元素内容为20
list<int> l4(l3.begin(),l3.end()); //创建一个链表其内容为l3的内容
list<int> l5(l4); //创建一个链表其内容为l4的内容
迭代器
遍历元素:
list<int> li={1,2,3,4,5,6};
for(list<int>::iterator it=li.begin();it!=li.end();it++){cout<<*it<<' ';
}
也可以使用auto
常用函数
empty():返回一个bool类型的值,只存在真和假,当链表为空时为真,不为空时为假
size():返回链表元素的个数
链表前插入push_front():表示在链表最前端插入一个数据
删除pop_front():表示在链表最前端删除一个数据
链表后插入push_back():表示在链表尾插入一个数据
删除pop_back():表示将链表尾删除一个数据
插入insert():插入元素到指定位置,通过在元素之前在指定位置插入新元素来扩展向量,从而有效地增加容器大小所插入的元素数量。
//插入单一数据到指定位置
iterator insert (iterator position, const value_type& val);
//插入一段数据到指定位置
void insert (iterator position, size_type n, const value_type& val);
//插入一段别的容器的数据到指定位置
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);//案例
li.insert(li.begin(),100); //在链表最前端插入数据100
li.insert(li.begin(),3,200); //在链表最前端插入3个数据内容为200
list<int> k(2,50); //创建一个新的链表k,其拥有2个元素内容均为50
li.insert(li.begin(),li.begin(),li.end()); //在链表v最前端插入链表上K的全部内容
erase():删除一个元素,或者是一段区间的元素,将会自动缩减空间使用。
iterator erase (iterator position);
iterator erase (iterator first, iterator last);//案例
li.erase(li.begin()); //删除
li.erase(li.begin(),li.begin()+4); //删除前4个元素
排序sort():让整个链表变成升序状态,或者变成自定义的排序状态
template <class Compare> void sort (Compare comp);//案例
#include<iostream>
#include<list>
using namespace std;
int cmp(const int &a,const int &b){ return a>b;//简单的自定义降序序列
}
int main(){list<int> li; //创建一个空链表for(int i=10;i>=6;i--){li.push_back(i);}li.push_front(3);li.push_back(20);list<int> li2(li);for(list<int>::iterator it=li.begin();it!=li.end();it++){cout<<*it<<' ';}cout<<endl;//排序前3 10 9 8 7 6 20//li.sort();for(list<int>::iterator it=li.begin();it!=li.end();it++){cout<<*it<<' ';}cout<<endl;//默认排序后3 6 7 8 9 10 20//li2.sort(cmp);for(list<int>::iterator it=li2.begin();it!=li2.end();it++){cout<<*it<<' ';}cout<<endl;//自定义排序后20 10 9 8 7 6 3//return 0;
}
reverse():
相对于自定义的降序方法,STL提供了一个默认的降序方法reverse(),类似于sort一样直接使用即可。
函数列表
Lst1.assign() 给list赋值
Lst1.back() 返回最后一个元素
Lst1.begin() 返回指向第一个元素的迭代器
Lst1.clear() 删除所有元素
Lst1.empty() 如果list是空的则返回true
Lst1.end() 返回末尾的迭代器
Lst1.erase() 删除一个元素
Lst1.front() 返回第一个元素
Lst1.get_allocator() 返回list的配置器
Lst1.insert() 插入一个元素到list中
Lst1.max_size() 返回list能容纳的最大元素数量
Lst1.merge() 合并两个list
Lst1.pop_back() 删除最后一个元素
Lst1.pop_front() 删除第一个元素
Lst1.push_back() 在list的末尾添加一个元素
Lst1.push_front() 在list的头部添加一个元素
Lst1.rbegin() 返回指向第一个元素的逆向迭代器
Lst1.remove() 从list删除元素
Lst1.remove_if() 按指定条件删除元素
Lst1.rend() 指向list末尾的逆向迭代器
Lst1.resize() 改变list的大小
Lst1.reverse() 把list的元素倒转
Lst1.size() 返回list中的元素个数
Lst1.sort() 给list排序
Lst1.splice() 合并两个list
Lst1.swap() 交换两个list
Lst1.unique() 删除list中重复的元素
set/multiset容器
set/multiset属于关联式容器,底层结构使用二叉树实现的。
set/multiset的特点是:所有的元素在插入时会自动被排序。
而set与multiset容器的区别就是:set容器中不允许有重复的元素,而multiset允许容器中有重复的元素。
构造和赋值
set<T> st 默认构造函数
set(const set &st) 拷贝构造函数
set& operator=(const set &st) 重载等号操作符
插入与删除
insert(elem) 在容器中插入元素
clear() 清除所有元素
erase(pos) 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end) 删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem) 删除容器中值为elem的元素
大小与交换
size() 返回容器中元素的数目
empty() 判断容器是否为空
swap(st) 交换两个集合容器
查找与统计
find(key) 查找key是否存在,若存在返回该键的元素的迭代器;若不存在,返回set.end()
count(key) 统计key的元素个数
案例:
#include<iostream>
#include <set>
using namespace std;
//set容器的查找与统计
int main() {set<int> s1;//插入数据s1.insert(20);s1.insert(30);s1.insert(10);s1.insert(40);//查找set<int>::iterator pos = s1.find(30);if (pos != s1.end()) {//找到元素cout << "找到该元素:" << *pos << endl;}else {cout << "未找到该元素" << endl;}//统计//这里需要注意set容器不予许出现重复的元素//因此count返回的值只能为0或者1//统计30的个数s1.insert(30);s1.insert(30);int num = s1.count(30);cout << "30的个数为:" << num << endl; //1return 0;
}
set与multiset容器的区别
- Multiset是set集合容器的一种,其拥有set的全部内容,在此基础之上,multiset还具备了可以重复保存元素的功能,因此会有略微和set的差别。
- Multise容器在执行insert()时,只要数据不是非法数据和空数据,insert就总是能够执行,无论时一个数据还是一段数据。
- Multiset容器中的find()函数回返回和参数匹配的第一个元素的迭代器,即时存在多个元素也只是返回第一个,如{10,20,20,20}搜索20进行匹配将会返回第二个参数,如果没有符合的参数则结束迭代器。
- 同理诸如lower_bound()等的需要进行一个位置的返回值,则统统返回第一个发现的值。
map/multimap容器
map容器中所有元素都是pair,pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)。
同时,所有元素都会根据元素的键值自动排序。
map/multimap属于关联式容器,底层数据结构是用二叉树实现的。它的优点就是可以根据key值快速找到value值。
这里需要了解map与multimap的区别:
即map不予许容器中有重复的key值元素;而multimap允许容器中有重复的key值元素,这里的区别与set与multiset十分类似。
Pair对组
pair只含有两个元素,可以看作是只有两个元素的结构体。对于成对出现的数据,利用对组可以返回两个数据。
应用:
- 代替二元结构体
- 作为map键值对进行插入
- 在创建pair对象时,必须提供两个类型名,两个对应的类型名的类型不必相同,可以在定义时进行成员初始化。
头文件:
#include<utility>
vs里面,某些编译器可以不声明这个头文件而直接使用,貌似在C++中,pair被放入了std命名空间中了。
格式为:
template <class T1, class T2> struct pair;
在现实情况中我们可以像类似于STL创建新容器一样创建pair也可以直接使用,如下:
pair<int,int> p;
pair<int,int> p(10,20);
或者是
map<char,int> m;
m.insert(pair<char,int>('a',10));
Pair数据访问
//数据类型
pair<string, int>p("公孙离", 17);
cout << "姓名:" << p.first << " 年岁:" << p.second << endl;
//和结构体类似,first代表第一个元素,second代表第二个元素
pair<char, float>p1=make_pair(‘p’,3.14);
cout << "字符:" << p1.first << " 小数:" << p1.second << endl;
make_pair
函数原型template pair make_pair(T1 a, T2 b) { return pair(a, b); }
可以通过make_pair生成我们的所需要的pair,对于一般的pair而言,如果需要对其进行赋值,则需要
pair<int,int> p;
p.first=10,p.second=20;
但如果使用make_pair方法,则可以变成如下内容:
pair<int,int> p;
p=make_pair(10,20);
可以看见,使用make_pair不仅仅让我们免去了对两个变量进行分开来的访问赋值,同时make_pair也智能的接受变量的类型,不需要再度指定,也就是说,make_pair本身是接受隐式类型转换的,比如定义的是一个int类型,使用make_pair传入一个float类型的参数,make_pair不会报错,而是回自动的进行一个类型转换,将float变为int,这样可以获得更高的灵活度,同时也会有一些小问题。
构造与赋值
map<T,T> mmap 默认构造函数
map(const map &mp) 拷贝构造函数
map& operator=(const map &mp) 重载等号操作符
案例:
#include<iostream>
#include<map>
using namespace std;
//map容器的构造与赋值
void printMap(map<int, int>& m) {for (auto it = m.begin(); it != m.end(); it++) {cout << "key =" << it->first << " value =" << it->second << endl;}cout << endl;
}
int main() {//创建map容器map<int, int> m;//插入数据里面需要传入的是对组m.insert(pair<int, int>(1, 10));//pair<int, int>(1, 10)为匿名二元组m.insert(pair<int, int>(3, 30));m.insert(pair<int, int>(4, 40));m.insert(pair<int, int>(2, 20));//插入元素后会根据key自动进行升序排列printMap(m);//拷贝构造map<int, int> m2(m);printMap(m2);//赋值map<int, int> m3;m3 = m2;printMap(m3);return 0;
}
大小与交换
size() 返回容器中元素的数目
empty() 判断容器中是否为空
swap(st) 交换两个集合容器
插入与删除
insert(elem) 在容器中插入元素
clear() 清除所有元素
erase(pos) 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end) 删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key) 删除容器中值为key的元素
案例:
#include<iostream>
#include <map>
using namespace std;
int main() {map<int, int> m;m.insert(pair<int, int>(1, 10));//插入第一种m.insert(make_pair(2, 20));//插入第二种m.insert(map<int, int>::value_type(3, 30));//插入第三种不建议使用//插入第四种最简单//[]不建议插入通过[]可以利用key访问到value//使用[]插入元素的时候,如果key不存在将会自动创建键值对m[4] = 40;printMap(m);m.erase(m.begin());//删除printMap(m);m.erase(3);//删除直接传入keyprintMap(m);//全部删除m.clear();//相当于m.erase(m.begin(),m.end())printMap(m);return 0;
}
查找与统计
find(key) 查找key是否存在,返回该键的元素的迭代器;若不存在返回map.end()
count(key) 统计key的元素的个数
案例:
#include<iostream>
#include<map>
using namespace std;
int main() {//查找map<int, int> m;m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(3, 30));m.insert(pair<int, int>(2, 20));//查找键为3的键值对map<int,int>::iterator pos=m.find(3);if (pos != m.end()) {cout << "查到了元素key=" << pos->first << " value=" << pos->second << endl;}else {cout << "未找到元素" << endl;}//统计//由于map容器中key不能重复出现因此count统计的结果只有0或1int num=m.count(3);//返回结果为整型cout << "num=" << num << endl;return 0;
}
Multimap容器
Multimap时map映射容器的一种,其拥有map的全部内容,并在此基础之上,multimap还具有了可以重复保存元素的功能,与上文的mutliset差不多,任何进行访问单个值得语句访问均只会返回第一个位置,这里不再多说,而是举一个实际中可能用得到得例子。
有没有一种方法,使得一个key值能够对应多个value,产生一种诸如一个学生有多门考试成绩一样的映射。
我们都知道map关联容器是使得一个数据与另一个数据发生映射的容器,通过key得到value产生一一对应,那么multimap在此基础上使得map元素可以重复,因此这种情况可以使用multimap。
相关文章:

【C++知识点】STL 容器总结
✍个人博客:https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 📚专栏地址:C/C知识点 📣专栏定位:整理一下 C 相关的知识点,供大家学习参考~ ❤️如果有收获的话,欢迎点赞👍…...

C++---背包模型---装箱问题(每日一道算法2023.3.9)
注意事项: 本题是"动态规划—01背包"的扩展题,dp和优化思路不多赘述。 题目: 有一个箱子容量为 V,同时有 n 个物品,每个物品有一个体积(正整数)。 要求 n 个物品中,任取若…...

if-else if与switch的练习1:输入两个数,输出两个数的加减乘除的值
1.if-else if的练习 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice…...

【教程】你现在还不知道微软的New Bing?你out了,快点进来看
哈喽啊,大家好,好久不见,我是木易巷! 不禁感叹,AI人工智能时代真的已经来临! 目前,谷歌和微软就各自面向大众的产品发布了重大公告。谷歌推出了一款名为Bard实验性对话式 AI 服务,而…...

https流程
ssl加密协议包含以下4个步骤 1、服务器去第三方机构注册生成证书,第三方机构非对称加密生成公钥私钥,给服务器一个私钥,证书包含了公钥。 2、客户端向服务器索要证书 3、客户端向第三方机构验证证书 4、客户端对称加密生成密钥,在…...

python魔法方法
Python中的魔法方法(也称为特殊方法或双下划线方法)是在类定义中使用的一些特殊的函数,可以使用dir方法查询。它们以双下划线开头和结尾,例如__init__和__str__。这些方法被Python解释器用于执行特定的操作,例如实例化对象、字符串…...

软件测试员如何进行产品测试?
一般来讲,当软件成为一个成功的产品后,产品测试工作就会复杂很多。比如拥有的用户量大,迭代频繁,测试的周期短,重复性强。面对紧张复杂的产品测试工作,软件测试员应怎样完成这一系列的测试工作呢࿱…...

计算机网络基础知识点【1】
文章目录计算机网络第一章 计算机网络参考模型1.计算机网络为什么需要分层?1.1 分层思想1.2 分层好处2.OSI七层模型2.1 OSI七层模型总结2.2 OSI七层工作原理2.3 数据封装与解封装2.4 计算机网络常用协议3.TCP/IP参考模型3.1 什么是TCP/IP协议3.2 TCP/IP协议族的组成…...

c++ 中标准库类型 string 详解
👁🗨👁🗨 前言 标准库类型string 表示可变长的字符序列,使用string 类型必须首先包含string 头文件。string 定义在命名空间std 中。 定义和初始化 string 对象 首先说明如何初始化对象是由类本身决定的࿰…...

Html新增属性之拖拽(drag)
元素在拖放过程中触发的事件 HTML5中,只要将元素的 draggable 属性设置为 true 就可以实现拖放功能,在拖放过程中,触发了多个事件,如下: dragstart:事件主体是被拖放元素,在开始拖放被拖放元素时触发。dra…...

C/C++开发,无可避免的多线程(篇二).thread与其支持库
一、原子类型与原子操作 1.1 原子类型与操作介绍 在前一篇博文中,多线程交互示例代码中,给出了一个原子类型定义: // 原子数据类型 atomic_llong total {0}; 那么什么事原子数据类型呢,和c的基础数据类型有什么不同呢:…...

mysql数据库之表级锁
表级锁,每次操作锁住整张表。锁定粒度大,发生所冲突的概率最高,并发度最低。应用在myisam、innodb、bdb等存储引擎中。 一、表级锁分类。 1、表锁 2、元数据锁(meta data lock,MDL) 3、意向锁 二、表锁…...

Python - Pandas - 数据分析(2)
Pandas数据分析2前言常用的21种统计方法describe():numeric_only:偏度skewness:功能:含义:计算公式:演示:峰度值:用途:数值:计算公式:演示&#x…...

我的十年编程路 2019年篇
随着2018年,三星天津研究院的裁撤,我选择了到广州的三星研究院工作,与最心爱的她开始一起生活。 这一年的开始,我注册了博客园。和2014年类似,在刚注册不久,我写了一篇题为《全新开始,全心出发…...

(蓝桥真题)剪格子(搜索+剪枝)
样例1输入: 3 3 10 1 52 20 30 1 1 2 3 样例1输出: 3 样例2输入: 4 3 1 1 1 1 1 30 80 2 1 1 1 100 样例2输出: 10 分析:这道题目我们直接从(1,1)点开始进行dfs搜索即可,但是需要注意一点的是我们搜…...

Kalman Filter in SLAM (3) ——Extended Kalman Filter (EKF, 扩展卡尔曼滤波)
文章目录1. 线性系统的 Kalman Filter 回顾2. Extended Kalman Filter 之 DR_CAN讲解笔记2.1. 非线性系统2.2. 非线性系统线性化2.2.1. 状态方程f(xk)f(x_k)f(xk)在上一次的最优估计状态x^k−1\hat{x}_{k-1}x^k−1处线性化2.2.2. 观测方程h(xk)h(x_k)h(xk)在这一次的预测…...

关于vertical-align的几问
vertical-align属性可以给我讲解一下吗? 当使用table-cell布局或inline元素时,可以使用CSS的vertical-align属性控制元素的垂直对齐方式。该属性可应用于元素本身以及其父元素(例如,td、th、tr和table)。 以下是vertic…...

【拜占庭将军问题】这一计谋,可以让诸葛丞相兴复汉室
我们都知道,诸葛亮第一次北伐是最可能成功的,魏国没有防备,还策反了陇西,陇西有大量的马匹可以装备蜀国骑兵,可惜街亭一丢,那边就守不住了 当时我不在,只能作诗一首~ 如果穿越过去,…...

【Linux】 -- make/Makefile
目录 Linux项目自动化构建工具 – make/Makefile 背景 依赖关系和依赖方法 多文件编译 项目清理 make原理 Linux项目自动化构建工具 – make/Makefile 背景 一个工程的源文件不计其数 按照其类型、功能、模块分别放在若干个目录当中 Makefile定义了一系列的规则来指定&…...

Forter 对支付服务商应对欺诈的四个建议和Gartner的两个关键结论
Gartner新版2023年度《线上欺诈检测市场指南》发布恰逢其时-企业正面临来自专业黑产和欺诈者与日俱增的压力。而在2023年,许多商户将调整反欺诈策略,对拒付率和转化率进行更严格的监测,以最大限度减少损失并增加营收。以下是Gartn…...

ANR系列(二)——ANR监听方案之IdleHandler
前言 关于IdleHandler,比较多同学错误地认为,这个Handler的作用是主线程空闲状态时才执行它,那么用它做一些耗时操作也没所谓。可是IdleHandler在主线程的MessageQueue中,执行queueIdle()默认当然也是执行在主线程中的࿰…...

数学小课堂:数学和自然科学的关系(数学方法,让自然科学变成科学体系。)
文章目录 引言I 数学方法,让自然科学变成科学体系。1.1 天文学1.2 博物学1.3 化学1.4 医药学1.5 物理学II 自然科学的升华过程III 数学方法的意义引言 19世纪初,英国人把采用实验的方法,系统地构造和组织知识,解释和预测自然的学问称为科学。 科学研究的是自然现象和自然…...

[蓝桥杯 2020 省 A1] 分配口罩
思路比较容易想到,因为口罩全部只有15批,因此直接暴力dfs搜索即可 //dfs #include<bits/stdc.h> using namespace std; int ans 9999; int num[] {9090400, 8499400, 5926800, 8547000, 4958200, 4422600, 5751200, 4175600, 6309600, 5865200, …...

第五章:C语言数据结构与算法之双向带头循环链表
系列文章目录 文章目录系列文章目录前言一、哨兵位的头节点二、双向链表的结点三、接口函数的实现1、创建结点2、初始化3、尾插与尾删4、头插与头删5、打印6、查找7、随机插入与随机删除8、判空、长度与销毁四、顺序表和链表的对比1. 不同点2. 优缺点五、缓存命中1、缓存2、缓存…...

一文带你了解,前端模块化那些事儿
文章目录前端模块化省流:chatGPT 总结一、参考资料二、发展历史1.无模块化引出的问题:横向拓展2.IIFE3.Commonjs(cjs)4.AMD引出的问题:5.CMD6.UMD7.ESM往期精彩文章前端模块化 省流:chatGPT 总结 该文章主要讲述了前端模块化的发展历史和各个…...

(六十五)大白话设计索引的时候,我们一般要考虑哪些因素呢?(中)
今天我们继续来说一下,在设计索引的时候要考虑哪些因素。之前已经说了,你设计的索引最好是让你的各个where、order by和group by后面跟的字段都是联合索引的最左侧开始的部分字段,这样他们都能用上索引。 但是在设计索引的时候还得考虑其他的…...

Spring事务管理
文章目录1 事务1.1 需求1.2 原因分析1.3 错误解决1.4 yml配置文件中开启事务管理日志1 事务 1.1 需求 当部门解散了不仅需要把部门信息删除了,还需要把该部门下的员工数据也删除了。可当在删除员工数据出现异常时,就不会执行删除员工操作,出…...

数字化工厂装配线生产管理看板系统
电力企业业务复杂,组织结构复杂,不同的业务数据,管理要求也不尽相同。生产管理看板系统针对制造企业的生产应用而开发,能够帮助企业建立一个规范准确即时的生产数据库。企业现状:1、计划不清晰:生产计划不能…...

vxe-grid 全局自定义filter过滤器,支持字典过滤
一、vxe-table的全局筛选器filters的实现 官网例子:https://vxetable.cn/#/table/renderer/filter 进入之后:我们可以参照例子自行实现,也可以下载它的源码,进行调整 下载好后并解压,用vscode将解压后的文件打开。全局…...

ECharts 环形图组件封装
一、ECharts引入1.安装echarts包npm install echarts --save2.引入echarts这里就演示全局引入了,挂载到vue全局,后面使用时,直接使用 $echartsimport * as echarts from echarts Vue.prototype.$echarts echarts二、写echarts组件这里演示环…...