前言:
STL(Standard Template Library),中文名标准模板库,是一个高效的C++程序库,包含很多常用的基本数据结构和基本算法,为C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
STL有六大组件:容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)。其中主要的是容器(用来管理某类对象的集合)、迭代器(用来在一个对象集合的元素上进行遍历操作)、算法(用来处理对象集合中的元素)三部分。
STL的基本观念就是将数据(数据由容器进行管理)和操作分离(由算法进行)。而迭代器在两者间充当粘合剂,是任何算法都可以和任何容器交互运作。
以下我只介绍了编程中常用到的容器。参考了资料,希望对大家有帮助,如果有错的地方,多多指点!!!
一、vector的常见用法详解
vector翻译为向量,一般叫变长数组,也就是长度根据需要而自动改变的数组。
1、vector的定义:vector<typename> name
(1)如果typename为整型、字符型、浮点型;
vector<int>name;
vector<double>name;
vector<char>name;
(2)如果typename为结构类型;
vector<node>name;
(3)如果typename为容器(vector、map、set...),定义的时候一定要在>>符号之间加上空格,因为一些使用c++11之前标准的编译器会把它视为移位操作,导致编译错误。
vector<vector<int> >name;
(4)数组a[]中的每一个元素都是一个vector
vector<typename>a[size];
2、vector容器内元素的访问
(1)通过下标访问,如vector<int>a,a[0]....a[a.size()-1].
(2)迭代器(iterator)访问,可以理解为一种类似指针的东西
vector<typename>::iterator it;
这样就得到了迭代器it,且可以通过*it来访问vector里的元素。
vector<int>a;
a.push_back(8);
a.push_back(8);
a.push_back(5);
a.push_back(2);
a.push_back(0);
vector<int>::iterator it=a.begin();///a.begin()为取首元素地址,而it指向这个地址
for(int i=0;i<a.size();i++)
printf("%d ",*(it+i));///等价于a[i]
///vector迭代器不支持it<a.end()写法
for(vector<int>::iterator it=a.begin();it!=a.end();it++)
printf("%d ",*it);
在常用STL容器中,只有vector和string允许使用a.begin()+i的写法。普及地,a.end()是尾元素地址地下一个元素。
3、vector常用函数实例解释
vector<int>a;
///push_back()在vector后面添加一个元素
a.push_back(8);
a.push_back(8);
a.push_back(5);
a.push_back(2);
a.push_back(0);
a.push_back(1);
///删除vector尾元素
a.pop_back();
int n=a.size();///获取vector元素个数
a.clear();///清空vector中的所有元素
a.insert(a.begin()+2,1);///将1插入到a[2]位置
a.erase(a.begin()+2);///删除a[2]这个元素
a.erase(first,last);///删除区间[first,last)内的所有元素
4、vector的常见用途
(1)储存数据
①vector可以作为数组使用,而且在一些元素个数不确定的场合可以很好地节省空间。
②有些场合需要根据一些条件把部分数据输出在同一行,数据中间用空格隔开。由于输出数据地个数是不确定地,为了更方便地处理最后一个满足条件地数据后面不输出额外地空格,可以先用vector记录所有需要输出地数据,最后一次性输出。
(2)用邻接表存储图
使用邻接表可以让一些对指针不太熟悉地读者有一个比较方便地写法。
二、set的常见用法详解
set翻译为集合,是一个内部自动有序且不含重复元素的容器。set的头文件为#include<set>,set内元素自动递增排序,且自动去除了重复元素。
1、set的定义写法和vector基本一致,typename可以为int、char、double、结构体、STL容器。
set<int>name;
set<double>name;
set<char>name;
set<node>name;
set<vector<int> >name;
set<int>a[size];
2、set容器内元素的访问:只能通过迭代器iterator访问。
set<int>a;
a.insert(8);
a.insert(8);
a.insert(5);
a.insert(2);
a.insert(0);
for(set<int>::iterator it=a.begin();it!=a.end();it++)
printf("%d",*it);
由于除了vector和string之外的STL容器都不支持*(it+i)的访问方式,通过*it来访问set里的元素。
3、set常见函数实例解析
set<int>a;
a.insert(8);///把8插入set容器中,自动去重和递增排序
a.insert(5);
a.insert(2);
set<int>::iterator it = a.find(2);///在set中查找2,返回对应值为2的迭代器
printf("%d",*it);///2
a.erase(it);///it为所要删除元素的迭代器
a.erase(it,a.end());///删除区间之间的信息
int n = a.size();///返回容器的个数
a.clear();///清空set容器的所有元素
4、set的常见用途
(1)set最重要的作用就是去重并按升序排序,因此喷到需要去重但却不方便直接开数组的情况。
(2)set中的元素是唯一的,如果需要处理不唯一情况,则需要使用multiset。
三、string常见用法详解
1、string的定义:string str;其也可以初始化。
2、string中的内容的访问
(1)通过下标访问:
string str="abcd";
for(int i=0;i<str.length;i++)
printf("%c",str[i]);
printf("%s\n",str.c_str());
(2)通过迭代器访问
string str="abcd";
string::iterator it;///string不像其他STL容器那样需要参数
for(string::iterator it = str.begin();it!=str.end();it++)
printf("%c",*it);
///string也可以和vector一样直接对迭代器加减某个数字
3、string常用函数实例解析
(1)string的加法
string str1="abc";
string str2="xyz";
string str;
str=str1+str2;///赋值于str
str1+=str2;///str2拼接在str1后
(2)string的比较
string str1="a";
string str2="aa";
string str3="abc";
string str4="xyz";
if(str1<str2) ...;///如果字典序str1<str2
if(str1!=str2) ...;///如果str1!=str2
if(str4>=str3) ...;///如果字典序str4>=str3
(3)length()或size()(容器元素的个数)、clear()(清空容器)。
(4)insert()(它有很多种写法),下面介绍常用的:
string str="abcxyz";
string str1="bao";
str.insert(3,str1);///在str[3]插入字符串str1
str.insert(it,first,last);///it插入[first,last)区间的子字符串
(5)erase(),与之前的容器的差不多。就是多了一个删除区间元素的方法
str.erase();///删除单个元素
str.erase(first,last);///删除区间[first,last)内的元素
str.erase(pos,length);///删除从起始位置pos的length个元素
(6)string::npos
string::npos用以作为find函数失配时的返回值,是一个常数,本身的值为-1或4294967295(unsigned_int最大值)
(7)substr(pos,len)、find()、replace()
string str="Hello World!";
str1=" ";
str.substr(3,5)///str.substr(pos,len)从pos开始、长度为len的子串
str.find(str1);///返回str出现子串str1第一次出现的位置。如果str1不是str子串,那么就返回string::npos
str.find(str2,pos);///从str固定位置pos开始匹配,返回值与上面一样
str2="Hi!";
str.replace(pos,len,str2);///从str位置pos开始、长度为len的子串替换str2
str.replace(it1,it2,str2);///用str的迭代器[it1,it2)范围内的子串替换str2
四、map的常见用法详解
map翻译为映射,也是常用的STL容器。在定义数组时,其实(如int a[10];)就是定义了从int型到int型的映射,比如a[3]=10;(从3映射到10),比如一个字典,提供了很多字符串和页码(字符串-->页码),如果用数组来定义会显得不方便。这时就考虑map吧,选择它没错,map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器)。
1、map的定义
map<typename1,typename2> mp;///<>内填写两个类型,其中第一个是映射前的类型typename1,一个是映射后的类型typename2
注意:如果字符串到整型的映射,必须是string而不能用char数组。(map<string,int>mp或map<set<int>,string>)
2、map容器内元素的访问
(1)下标访问:map中的键是唯一的,比如map<char,int>mp,mp['c']=20。
(2)通过迭代器访问:map的迭代器的定义和其他容器的定义都是一样的,但是其迭代器的使用方式与其他STL容器的不同。使用it->first访问键,使用it->second访问键。
map<char,int> mp;
mp['m']=20;
mp['n']=30;
for(map<char,int>::iterator it = mp.begin();it!=mp.end();it++)
printf(%d %d\n,it->first,it->second);
3、map常见函数实例解析
map<char,int> mp;
mp['m']=20;
mp['n']=30;
mp.find(key);///返回键为key的映射的迭代器
map<char,int>::iterator it = mp.find('m');
mp.erase(it);///删除m
mp.erase(first,last);///删除区间[first,last);
int len = mp.size();///获取容器内的个数
mp.clear();///清空容器
4、map的容器常见用途
(1)需要建立字符或字符串与整数之间映射的题目,使用map可以减少代码量
(2)判断大整数或其他类型数据是否存在的题目,可以把map当bool数组用。
(3)字符串和字符串的映射也有可能会遇到。
map的键和值是唯一的,如果一个键需要对应多个值,就只能用multimap。
五、queue的常见用法详解
queue翻译为队列,在STL中主要则是实现了一个先进先出的容器。
1、queue的定义:queue<typename> name;
2、queue容器内元素的访问(只能通过front()来访问队首元素,或是通过back()来访问队尾元素)
3、queue常用函数实例解析
queue<int>q;
q.push(1);
q.push(3);
q.push(2);///2入队
printf(%d %d %d\n,q.front(),q.back(),q.size());///可以分别获得队首元素和队尾元素,获取队列内元素个数
q.pop();///队首元素出队
if(!q.empty()) ...;///检测队列是否为空
注意:使用front()和pop()函数前,必须用empty()判断队列是否为空。
4、queue的常见用途
(1)方便实现广度优先搜索
(2)STL的容器中还有两种容器跟队列有关,分别是双端队列deque和优先队列priority_queue,前者是首尾皆可插入和删除的队列,后者是使用堆实现的默认将当前队列最大元素置于队首的容器。
六、priority_queue的常见用法详解
priority_queue又称为优先队列,其底层用堆来实现的,在优先队列中,队首元素一定是当前队列中优先级最高的那一个。
1、priority_queue的定义:priority_queue<typename>name;
2、priority_queue容器内元素的访问
和队列不同,priority_queue只能通过top()函数来访问队首元素(也可以称为堆顶元素),也就是优先级别最高的元素。
3、priority_queue常用函数实例解析
priority_queue<int>q;
q.push(1);
q.push(3);
q.push(2);///2入队
printf(%d %d\n,q.top(),q.size());///可以分别获得队首元素,获取队列内元素个数
q.pop();///队首元素出队
if(!q.empty()) ...;///检测队列是否为空<int>q;
4、priority_queue内元素优先级的设置
(1)基本数据类型的优先级设置
基本数据类型就是int型、double型、char型等可以直接使用的数据类型,优先队列对他们优先级设置一般是数字大的优先级越高
priority_queue<int,vector<int>,less<int> >q;///等价priority_queue<int>q
q.push(2);
q.push(3);
q.push(1);
printf("%d\n",q.top());///输出3
vector<int>来自承载底层数据结构堆的容器,less<int>表示数字越大的优先级越大,greater<int>表示优先级别越小。
(2)结构体的优先级设置
struct fruit{
string name;
int price;
friend bool operator < (fruit f1,fruit f2){///重载,不能是大于号,否则会编译出错
return f1.price < f2.price;///价格高的水果优先级高(从低到高),否则>就是价格低的水果优先级低(从高到低)
}
///如果结构内的数据比较庞大,可以在参数使用引用,const fruit f1、const fruit f2
}
friend这个是友元,是减少系统开销,提高效率的。注意:优先队列的这个函数与sort中的cmp效果相反。
5、priority_queue的常见用途
(1)贪心问题
(2)Dijkstra算法进行优化
七、stack的常见用法详解
stack翻译为栈,是STL中实现的先进先出的容器。
1、stack常见函数实例
stack<int>st;
st.push(1);
st.push(3);
st.push(2);///入栈
int x=st.top();///取栈顶元素
st.pop();///删除栈顶元素
int n = st.size();
if(!st.empty()) ....;///判断栈是否为空
2、stack的常见用途
用来模拟实现一些递归,防止程序对栈内存的限制,而导致程序运行出错
八、pair的常见用法详解
pair是一个非常实用容器,当想要将两个元素绑在一起作为一个合成元素、又不想因此定义结构体,使用pair可以很方便地作为一个代替品,pair实际上可以看作一个内部有两个元素地结构体,且两个元素地类型是可以指定的。(头文件utility,map头文件会自动添加utility头文件)
struct pair{
typename1 first;
typename2 second;
}
1、pair的定义
pair有两个参数,分别对应first和second的数据类型,它们可以是任意基本数据类型或容器。
2、pair中元素的访问
pair中只有两个元素,分别是first和second,只需要按正常结构体的方式去访问即可。
///pair<typename1,typename2>name;
pair<string,int>p;
p.first="Hello";
p.second=3;///初始化
pair<string,int>p("Hello",3);///初始化
///临时构建一个pair
p=pair<string,int>("Hello",3);
p=make_pair("Hello",3);///使用自带函数
3、pair常用函数实例解析
比较操作数:比较规则(==,!=,<,<=,>,>=)先以first的大小为标准,只有当first相等才去判断second的大小。
pair<int,int>x(1,2);
pair<int,int>y(1,1);
pair<int,int>z(2,3);
if(x>y) ....;///first相等,比较second
if(y<z) ....;///比较first
4、pair的常见用途
(1)是来代替二元结构体及其函数,可以节省编码时间。
(2)作为map键值对来进行插入。
map<string,int>mp;
mp.insert(make_pair("Hello",3));
mp.insert(pair<string,int>("Hi",5));
for(map<string,int>::iterator it=mp.begin();it!=mp.end();it++)
cout<<it->first<<" "<<it->second<<endl;
九、参考资料
1、https://blog.csdn.net/TeFuirnever/article/details/104438908?utm_source=app(【C++100问】深度总结STL基本容器的使用)
2、《算法笔记》