当前位置: 首页 > news >正文

STL库里的常用容器

前言:之前的文章经常使用一些STL库提供的容器以及其包含的算法来简化代码编写,但都是让大家自己去学习下,不知道大家有没有去学下,本篇简单总结介绍下几种常用的容器及其使用。

string

字符串类与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<s.size();i++){
	cout<<s[i];                   //通过下标访问
}    
for(auto i:s){                    //基于范围的for循环
    cout<<i;
}
//也可使用迭代器但没必要

常用函数

string s;
cin>>s;                   //遇到空格会结束
getline(cin,s);           //获取一行字符串,但会读取前面的换行符(若前面有cin,getline会处理自身结尾的换行符),可用cin.ignore()处理,丢弃前面的换行符
string s1="abc",s2="aaa";
cout<<(s1>s2);                //字符串比较直接用>,<,==,!=
string s="abc";
cout<<s.size();             //返回字符串长度
s.clear();                  //清空字符串
cout<<s.empty();            //判断字符串是否为空,是返回1,否返回0
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!";      //包含在<algorithm>头文件
if(s1.find("llo")!=-1){        //从左向右找第一次出现"llo"的位置,找到则返回第一个元素的下标,若没找到则返回-1
	cout<<s1.find("llo");
}
s1.find('o',5);                //从下标为5的位置开始寻找'o'
if(s1.rfind('o')!=-1){         //从右往左找第一次出现'o'的位置
	cout<<s1.rfind('o');
}
if(s1.find_first_of("world")!=-1){       //从左往右找第一个出现的子串(字符串的任意子串)
	cout<<s1.find_first_of("world");     //第一个子串是'l' 
}
//find_first_not_of(),找第一个不是子串的位置
//find_last_of(),从右往左找第一个
string s="fedbca";         //s.end()是最后一个元素的后一个位置
sort(s.begin(),s.end());   //对s中元素从小到大排序(左闭右开)
string s="ABC";
reverse(s.begin(),s.end());      //翻转字符串,包含在<algorithm>头文件

 字符串数组

string s[4]={"ling","yi","er","san"}; 
char a[10][15]={"ling","yi","er","san"};  //二维字符数组

vector

动态数组,是存储任意相同类型的、大小可变的数组,能自动管理内存(不像C语言中的数组在定义时要给定数组大小)。在使用其中的函数时要引入头文件

#include<iostream>
#include<vector>        //引入<vector>头文件
using namespace std;    //vector容器是属于std命名空间的

定义与初始化

vector<int>v1;                //定义一个整型的空数组
vector<int>v2{1,2,3,4,5};     //列表初始化一个包含5个整形元素的数组
vector<int>v3(5);             //定义一个大小为5的数组,元素默认为0
vector<int>v4(5,1);           //定义一个大小为5的数组,元素都为1
vector<int>v5=v2;             //可以直接用=拷贝

元素访问

cout<<v2[2];         //与普通数组一样,可通过下标访问(从0开始)
for(vector<int>::iterator it=v2.begin();it!=v2.end();it++){    //通过迭代器访问,定义为vector<type>::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<<i<<" ";
}
cout<<v2.back();                //返回最后一项的值

添加元素 

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<<v2.size();                      //返回数组中元素的个数
cout<<v.empty();                      //判断数组是否为空,是返回true,否返回false
cout<<(v==v2);                          //可直接用==判断其中元素是否相等
sort(v.begin(),v.end());               //对v所有元素从小到大排序,包含在<algorithm>头文件中
sort(v.begin(),v.end(),cmp);           //和普通sort一样,可自定义比较函数
reverse(v.begin(),v.end());     //将数组中的元素前后翻转,包含在<algorithm>头文件
auto it=find(v2.begin,v2.end(),2);      //返回元素2在v2中第一次出现的位置,包含在<algorithm>头文件
if(it!=v2.end()){                       //it是迭代器类型
    cout<<"找到了!"<<endl;
    cout<<it-v2.begin();                //返回第一次出现的下标
}

二维数组

vector<vector<int>>v;              //创建一个空的二维数组,每个元素都是一个vector<int>类型的容器,每行的长度和列的长度都可动态改变(行与行在内存中不一定是连续存储的)
vector<int>v1[10];                 //一个包含10个vector<int>元素的数组,也是二维数组,但第一维大小固定为10(在内存中连续存储)
vector<vector<int>>v2(n+1,vector<int>(m+1,0));   //大小为n+1的vector容器,每个元素是大小为m+1的vector容器,初始值为0 
vector<vector<int>>v{{1,2},{3,4}};
v[0].push_back(3);                //在某一行添加元素
v.push_back({5,6});               //添加新行  ||v.push_back(vector<int>{5,6})
vector<vector<int>>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<vector<int>>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

pair是一个模板类,它用于将两个不同类型的数据组合成一个单一的对象,通常用于表示键值对或其他需要组合两种数据的场景

初始化

pair<string,int>p1;         //创建一个默认初始化的pair,pair.first="",pair.second=0
pair<string,int>p2{"Mike",1};      //直接初始化         
pair<string,int>p3=make_pair("Mike",1);    //通过make_pair函数

成员访问 

cout<<p2.first<<" "<<p2.second;     //使用"."运算符

 pair支持比较操作,先比较first成员,若first成员相等,则比较second成员

pair<string,int>p1{"1",1};
pair<string,int>p2{"2",0};
if(p2>p1){
	cout<<"p2>p1";
}

map

关联容器,以键值对的形式存储数据(每个键值对都是一个pair对象),键是唯一的,主要用于"一对一"映射的情况。map的内部逻辑是红黑树(一种自平衡二叉搜索树),会自动将数据按键从小到大有序存储,由于其基于红黑树的实现,查找、插入和删除操作的时间复杂度均为 O(logn)。

在使用时要包含头文件<map>

#include<map>

创建

map<string,int>mp1;     //创建一个空的map
map<string,int>mp2{{"Jane",1},{"Mike",2}};   //初始化列表创建
map<string,int>mp3{mp2};      //拷贝另一个map创建

插入元素

mp.insert({"Mary",1});          //使用insert方法
mp["John"]=2;            //类似数组的方式增加元素,若键存在,修改其对应值;若不存在,添加此键值对

查找元素

auto it=mp.find("Mary");       //使用迭代器(此处小编直接用auto了,若不嫌麻烦可与上文一样创建迭代器)
if(it!=mp.end()){
    cout<<it->second;
}else{
    cout<<"Not found";
}

cout<<mp["Mary"];       //使用下标运算符,若键不存在,会用默认值创建

删除元素

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<<it->first<<" "<<it->second<<endl;     //迭代器要用键的别名first,值的别名second 
}

for(auto item:mp){                              //基于范围的for循环
    cout<<item.first<<" "<<item.second<<endl;   //每个元素都是一个pair对象,用"."
}

By the way(顺便说一句,主播最近也在学英语,是这个意思吧),empty(),size(),clear()这些方法大部分都是通用的

set

关联容器,用于存储唯一元素(其中的元素不重复),set内部也使用红黑树来实现,会将元素自动从小到达排序,提供了高效的插入、删除和查找操作。

使用时需包含头文件<set>

#include<set>

创建

set<int>st1;
set<int>st2{1,2,3,4,5};
set<int>st3{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<<item<<" ";
}

queue

一种容器适配器,用于实现先进先出(FIFO,First-In-First-Out)的数据结构,其中元素从队尾插入,从队头移除,队列的大小可以根据需要动态调整。

使用需包含头文件<queue>

#include<queue>

声明和初始化 

queue<int>q1;         
queue<int>q1{q2};
//queue是一个容器适配器,其设计初衷是提供一个简单的先进先出数据结构,因此它不支持初始化列表的构造函数

插入、移除 

q1.push(2);             //在队尾插入元素2
q1.pop();               //移除队首元素

访问队头和队尾 

cout<<q.front();           //队头
cout<<q.back();            //队尾

一个通用的好用STL算法

lower_bound()在一个已排序好的序列中,找到第一个大于等于(不小于)给定值的元素,并返回指向该元素的迭代器;如果容器中所有元素都小于给定值,则返回尾迭代器.查找逻辑是二分查找。

使用需包含头文件<algorithm>

使用示例

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
int main(){
	set<int>st{1,2,4,6,8,10};
	auto it=st.lower_bound(5);
    if(it!=st.end()){
        cout<<*it<<endl;
    } else {
        cout<<"All elements are less than 5"<<endl;
    }
	return 0;
} 

upper_bound()同理,用于在有序序列中查找第一个大 给定值的元素。

unordered_set

内部基于哈希表实现(哈希表是一种通过哈希函数将键映射到存储位置的数据结构),能够快速地插入、查找和删除元素(比set快,对时间复杂度要求高可用),元素存储顺序是无序的,且是唯一的。

使用示例

#include<iostream>
#include<unordered_set>
#include<algorithm>
using namespace std;
int main(){
	unordered_set<int>st{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<<x<<" ";
	}
	return 0;
} 

相关文章:

  • Redis 缓存 + MySql 持久化 实现点赞服务
  • kotlin协程
  • C++ Socket优化实战:提升网络应用的性能与效率
  • Prompt攻击
  • C++ 入门二:C++ 编程预备知识
  • JavaScript中Reflect对象指南:更智能的对象操作
  • BLE 协议栈事件驱动机制详解
  • Codeforces Round 1016 (Div. 3)题解
  • Django软删除功能完整指南:构建图书馆项目
  • 【Docker项目实战】使用Docker部署ToDoList任务管理工具
  • 亮相CMEF,美的医疗全维度打造智慧医疗新生态
  • HTML的Canvas元素
  • 数字的乘阶运算
  • 零碳园区智慧能源解决方案
  • 【算法学习】链表篇:链表的常用技巧和操作总结
  • SvelteKit 最新中文文档教程(19)—— 最佳实践之身份认证
  • 控制 ElementUI el-table 树形表格多选框的显示层级
  • NLP高频面试题(三十七)——大模型训练和推理的显存估计
  • 深入解析原生鸿蒙中的 RN 日志系统:从入门到精通!
  • Go 语言中的select是做什么的
  • 农村网站建设必要性/播放量自助下单平台
  • 电子商务网站建设步骤百度文库/软文网官网
  • node怎么做网站/百度客服人工服务电话
  • wordpress 没有注册/seo技术学院
  • 个性化网站设计/seo和点击付费的区别
  • 内部网站开发/什么是关键词