前言:之前的文章经常使用一些STL库提供的容器以及其包含的算法来简化代码编写,但都是让大家自己去学习下,不知道大家有没有去学下,本篇简单总结介绍下几种常用的容器及其使用。
字符串类与C语言char数组的不同:string没有字符串结尾标识'\0',不能用printf()输出,但C++提供了printf访问字符串的接口——函数data()或者c_str()
string s="hello world";
printf("%s\n%s",s.data(),s.data());
定义和初始化
string s; //创建一个空字符串
string s1="Hello world!"; //直接初始化
string s2("Hello world!"); //完全拷贝
string s2(s1);
string s2=s1;
string s2(s1,0,5); //部分拷贝,从下标0的位置开始取5个字符拷贝给s2
string s2("Hello world!",0,5)
string s2(s1,1); //从下标1的位置拷贝到末尾
string s3(4,'a'); //用4个字符'a'初始化字符串
string s2=s1.substr(0,5); //s.substr(起始位置下标,长度) 截取子串,若长度缺省则截取到最后
拼接
string s1="abc",s2="def";
string s3=s1+s2; //直接用'+'拼接
s1.append(s2); //使用连接函数append()
s1.append(s2,0,3); //可拼接部分(s2从下标1开始的3个字符)
s1.append(4,'d'); //在末尾添加4个'd'
s1.insert(2,2,'a'); //在下标为2的位置插入两个'a'
删除
string s1="hello world!";
s1.erase(5,7); //删除从第5个开始的7个字符
s1.erase(1); //删除从第1个开始往后所有的字符
遍历
string s="abcdef";
for(int i=0;i
常用函数
string s;
cin>>s; //遇到空格会结束
getline(cin,s); //获取一行字符串,但会读取前面的换行符(若前面有cin,getline会处理自身结尾的换行符),可用cin.ignore()处理,丢弃前面的换行符
string s1="abc",s2="aaa";
cout<<(s1>s2); //字符串比较直接用>,<,==,!=
string s="abc";
cout<
string s1="hello world!";
s1.replace(6,5,"jane"); //将从第6位开始的5个元素替换为jane
s1.replace(6,5,"iamjane",3,4); //替换为后面字符串从第3位开始的4位个元素
s1.replace(6,5,4,'x'); //替换为4个'x'
string s1="hello world!"; //包含在头文件
if(s1.find("llo")!=-1){ //从左向右找第一次出现"llo"的位置,找到则返回第一个元素的下标,若没找到则返回-1
cout<
string s="fedbca"; //s.end()是最后一个元素的后一个位置
sort(s.begin(),s.end()); //对s中元素从小到大排序(左闭右开)
string s="ABC";
reverse(s.begin(),s.end()); //翻转字符串,包含在头文件
字符串数组
string s[4]={"ling","yi","er","san"};
char a[10][15]={"ling","yi","er","san"}; //二维字符数组
动态数组,是存储任意相同类型的、大小可变的数组,能自动管理内存(不像C语言中的数组在定义时要给定数组大小)。在使用其中的函数时要引入头文件
#include
#include //引入头文件
using namespace std; //vector容器是属于std命名空间的
定义与初始化
vectorv1; //定义一个整型的空数组
vectorv2{1,2,3,4,5}; //列表初始化一个包含5个整形元素的数组
vectorv3(5); //定义一个大小为5的数组,元素默认为0
vectorv4(5,1); //定义一个大小为5的数组,元素都为1
vectorv5=v2; //可以直接用=拷贝
元素访问
cout<::iterator it=v2.begin();it!=v2.end();it++){ //通过迭代器访问,定义为vector::iterator it;
cout<<*it<<" "; //迭代器可以近似理解为指针,通过*it访问其元素
}
for(auto it=v2.begin();it!=v2.end();it++){ //也可用auto自动类型推导
cout<<*it<<" ";
}
for(auto rit=v2.rbegin();rit!=v2.rend();rit++){ //反向迭代,v.rbegin()+1是倒数第二项
cout<<*rit<<" ";
}
for(auto i:V2){ //还可用基于范围的for循环遍历v2中的每个元素
cout<
添加元素
v2.push_back(6); //在数组末尾添加元素6
v2.insert(v.begin(),0); //在首元素前面插入一个0
v2.insert(v.begin()+2,6); //在下标为2的位置前面插入一个6
v2.insert(v.begin(),3,6); //在首元素前面插入3个6
v.insert(v.begin(),v2.begin(),v2.end()); //在v容器前面插入v2容器(容器拼接)
删除元素
v2.pop_back(); //删除数组的最后一个元素
v2.erase(v2.begin()+1); //删除下标为1的元素
v2.erase(v2.begin()+1,v2.begin()+5); //删除下标从1到4的一段元素(左闭右开)
v2.erase(v2.begin(),v2.end()); //删除所有元素
v2.clear(); //清除所有元素
常用函数
cout<
sort(v.begin(),v.end()); //对v所有元素从小到大排序,包含在头文件中
sort(v.begin(),v.end(),cmp); //和普通sort一样,可自定义比较函数
reverse(v.begin(),v.end()); //将数组中的元素前后翻转,包含在头文件
auto it=find(v2.begin,v2.end(),2); //返回元素2在v2中第一次出现的位置,包含在头文件
if(it!=v2.end()){ //it是迭代器类型
cout<<"找到了!"<
二维数组
vector>v; //创建一个空的二维数组,每个元素都是一个vector类型的容器,每行的长度和列的长度都可动态改变(行与行在内存中不一定是连续存储的)
vectorv1[10]; //一个包含10个vector元素的数组,也是二维数组,但第一维大小固定为10(在内存中连续存储)
vector>v2(n+1,vector(m+1,0)); //大小为n+1的vector容器,每个元素是大小为m+1的vector容器,初始值为0
vector>v{{1,2},{3,4}};
v[0].push_back(3); //在某一行添加元素
v.push_back({5,6}); //添加新行 ||v.push_back(vector{5,6})
vector>v{{1,2},{3,4}};
v[0].erase(v[0].begin(),v[0].end()); //删除v[0]中的所有元素,v[0]变成空数组,v的大小为1
//v变为 {{},{3,4}}
//v.erase(v[0].begin(), v[0].end())是错误的,erase方法需要的是外层容器的迭代器范围,而 v[0].begin()和v[0].end() 是子向量的迭代器
vector>v{{1,2},{3,4},{5,6}};
v.erase(v.begin()+1); //v[1]空间被删除,v的大小变为2,后续元素的索引向前移动
//v变为 {{1, 2}, {5, 6}}
v[0].clear(); //删除v[0]中的所有元素,v[0]变为空数组
pair是一个模板类,它用于将两个不同类型的数据组合成一个单一的对象,通常用于表示键值对或其他需要组合两种数据的场景
初始化
pairp1; //创建一个默认初始化的pair,pair.first="",pair.second=0
pairp2{"Mike",1}; //直接初始化
pairp3=make_pair("Mike",1); //通过make_pair函数
成员访问
cout<
pair支持比较操作,先比较first成员,若first
成员相等,则比较second
成员
pairp1{"1",1};
pairp2{"2",0};
if(p2>p1){
cout<<"p2>p1";
}
关联容器,以键值对的形式存储数据(每个键值对都是一个pair对象),键是唯一的,主要用于"一对一"映射的情况。map的内部逻辑是红黑树(一种自平衡二叉搜索树),会自动将数据按键从小到大有序存储,由于其基于红黑树的实现,查找、插入和删除操作的时间复杂度均为 O(logn)。
在使用时要包含头文件
#include
创建
mapmp1; //创建一个空的map
mapmp2{{"Jane",1},{"Mike",2}}; //初始化列表创建
mapmp3{mp2}; //拷贝另一个map创建
插入元素
mp.insert({"Mary",1}); //使用insert方法
mp["John"]=2; //类似数组的方式增加元素,若键存在,修改其对应值;若不存在,添加此键值对
查找元素
auto it=mp.find("Mary"); //使用迭代器(此处小编直接用auto了,若不嫌麻烦可与上文一样创建迭代器)
if(it!=mp.end()){
cout<second;
}else{
cout<<"Not found";
}
cout<
删除元素
mp.erase("Mary"); //使用erase方法,删除键为"Mary"的元素
auto it=mp.find("Mary");
if(it!=mp.end()){
mp.erase(it); //删除迭代器指向元素
}
遍历元素
for(auto it=mp.begin();it!=mp.end();it++){ //使用迭代器
cout<first<<" "<second<
By the way(顺便说一句,主播最近也在学英语,是这个意思吧),empty(),size(),clear()这些方法大部分都是通用的
关联容器,用于存储唯一元素(其中的元素不重复),set内部也使用红黑树来实现,会将元素自动从小到达排序,提供了高效的插入、删除和查找操作。
使用时需包含头文件
#include
创建
setst1;
setst2{1,2,3,4,5};
setst3{st2};
插入,查找,删除
st2.insert(6); //插入元素6
auto it=st2.find(3); //查找元素3
if(it!=st2.end()){
cout<<*it;
}else{
cout<<"Not find";
}
st2.erase(3); //删除元素3
遍历元素
for(auto it=st2.begin();it!=st2.end();it++){ //使用迭代器
cout<<*it<<" ";
}
for(auto item:st2){ //基于范围的for循环
cout<
一种容器适配器,用于实现先进先出(FIFO,First-In-First-Out)的数据结构,其中元素从队尾插入,从队头移除,队列的大小可以根据需要动态调整。
使用需包含头文件
#include
声明和初始化
queueq1;
queueq1{q2};
//queue是一个容器适配器,其设计初衷是提供一个简单的先进先出数据结构,因此它不支持初始化列表的构造函数
插入、移除
q1.push(2); //在队尾插入元素2
q1.pop(); //移除队首元素
访问队头和队尾
cout<
lower_bound()在一个已排序好的序列中,找到第一个大于等于(不小于)给定值的元素,并返回指向该元素的迭代器;如果容器中所有元素都小于给定值,则返回尾迭代器.查找逻辑是二分查找。
使用需包含头文件
使用示例
#include
#include
#include
using namespace std;
int main(){
setst{1,2,4,6,8,10};
auto it=st.lower_bound(5);
if(it!=st.end()){
cout<<*it<
upper_bound()同理,用于在有序序列中查找第一个大 给定值的元素。
内部基于哈希表实现(哈希表是一种通过哈希函数将键映射到存储位置的数据结构),能够快速地插入、查找和删除元素(比set快,对时间复杂度要求高可用),元素存储顺序是无序的,且是唯一的。
使用示例
#include
#include
#include
using namespace std;
int main(){
unordered_setst{2,5,6,4,8,9};
st.insert(11);
auto it=st.find(4);
if(it!=st.end()){
st.erase(4); //st.erase(it)
}
for(int x:st){
cout<