从来好事天生俭,自古瓜儿苦后甜。这篇文章主要讲述C++学习之旅第六站:让我们一起走进 STL库相关的知识,希望能为你提供帮助。
一.定义
STL(standard template library),中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。
二.组成部分
STL包含 容器、算法、迭代器、函数对象、适配器、内存分配器 六大组件
主要包含容器、迭代器和算法三个部分
容器(containers):用来管理某类对象的集合。每一种容器都有其优点和缺点,根据我们使用中的不同需求,我们可以根据需要从STL提供的七种基本容器中进行选择。
迭代器(literators):用来在一个对象集合的元素上进行遍历动作。这个对象集合或许是个容器,或许是容器的一部分。每种容器都提供了自己的迭代器。
算法(Algorithms):用来处理对象集合的元素,比如Sort,Search,Copy等元素,由于迭代器提供了一致的接口,在其帮助下,我们可以通过写一次算法,就可以将其运用于任何容器上。
STL 的基本观念就是将数据和操作分离。容器(管理数据),算法(执行操作),迭代器(充当二者粘合剂),目的:使任何算法都可以和任何容器交互运作。
在c++标准中,STL包含了13个头文件
三.容器和适配器(一)容器
如下所示:
【C++学习之旅第六站(让我们一起走进 STL库)】
<
iterator>
<
functional>
<
vector>
<
deque>
<
list>
<
queue
<
stack>
<
set>
<
map>
<
algorithm>
<
numeric>
<
memory>
<
utility>
容器:一种模板类的集合,封装的是组织数据的方式(即数据结构)
I.分类
如图所示,我们可以根据不同的需求来选择合适的形状和大小的物件来实现我们的目的,例如给小孩买个盛水的容器,我们会选择水杯,绝不会选择如桶或盆之类的物品,既避免了浪费,也满足了需要。
在程序开发过程中,存储数据的方式和处理数据的算法同等重要,存储数据的方式直接决定了在对数据进行基本操作(增、删、查、修、序)时的复杂度的高低。
(1)序列式容器(Sequence containers)
II.序列式容器
定义
向量(vector) 、
双端队列(deque)、列表(list)
(2)关联式容器( Associatative container)
集合(set)
、
多重集合(multiset)
映射(map)
、
多重映射(multimap)
线性排列(类似普通数组的存储方式)来存储某一指定类型(例如 int、double、float等),该容器并不会对数据进行排序,包含
分类
array<
T,N>
(数组容器):表示可以存储N个T类型的数据,一旦建立,长度不变(静态),不能进行删除和增加操作,只能进行改变元素的的值操作。
vector<
T>
(向量容器):用来存放T类型容器,长度可以根据需要变化(动态),在尾部添加和删除的复杂度为O(1)常数阶。
deque<
T>
(双端队列容器):和vector类似,但不同的是,在头部插入 或 删除也很高效,复杂度也是O(1)的常数阶。
list<
T>
(双向链表容器):类型为T且长度可变的容器,在进行插入和删除操作时,其复杂度为O(1)的常数阶,但缺点为在进行查找是,他是从 “ 最前一端点往后
”或“ 最后一端点往前 ”
开始顺序查找,查找速度比前三种要慢。
forward_list<
T>
(正向链表容器):长度可变,以单链表的形式存储元素,速度相交与双链表更快,也更节省空间
理解图形如下:
(1)array<
T,N>
容器
操作功能表如下:
代码解释如下:
#include<
iostream>
#include<
array>
using namespace std;
int main()
array<
int,7>
values5,4,3,2,1,-1,6;
//定义并初始化数组
array<
int,7>
values19,8,7,5,4,3,2;
//迭代器(iterators)
auto a=values.begin();
//返回指向容器中第一个元素的随机访问迭代器(类似c中的指针)
auto b=values.end();
//返回指向容器中最后一个元素之后一个位置的随机访问迭代器
auto c=values.rbegin();
//返回指向容器中最后一个元素的随机访问迭代器
auto d= values.rend();
//返回指向第一个元素前一位置的随机访问迭代器
//values.cbegin()、values.cend()、values.crbegin()、values.crend()
//结果和以上类似,但是多了一个在此基础上不需修改的特性
auto e=values.cbegin();
//*e=8;
(由于已被const修饰,不可以再被更改)
cout<
<
" a =" <
<
*a<
<
" b ="<
<
*b <
<
" c="<
<
*c<
<
" d=" <
<
" "<
<
" e="<
<
*e<
<
endl;
//因为返回的值为指针,所以要用“*”来取值
cout<
<
\\n;
//容量(Capacity)
int size=values.size();
//返回当前容器存储元素的总数,其值失踪等于初始化的N
int length=values.max_size();
//返回容器可容纳元素总数,其值始终等于初始化的N
int g = values.empty();
//如果空的话,返回1,反之,返回0
cout<
<
"当前元素总数为"<
<
size<
<
" 容器可容纳元素总数为 "<
<
length<
<
" g= "<
<
g<
<
endl;
cout<
<
\\n;
//元素访问(Element access)
//operator[]用法请参考 http://www.cplusplus.com/reference/array/array/operator[]/
int data=https://www.songbingjia.com/android/values.at(5);
//返回位置5(数组下标)处的值
int first=values.front();
//返回第一个元素的值
int end = values.back();
//返回最后一个元素的值
//get<
locate>
(数组名) :输出数组指定位置的元素
auto f=values.data();
//返回指向第一个元素的指针
cout<
<
"data= "https://www.songbingjia.com/android/<
<
data<
<" first= "<
<
first<
<
" end= "<
<
end<
<
" f= "<
<
*f<
<
endl;
cout<
<
\\n;
//修饰语(Modifiers)
values.fill(4);
//将数组中所有元素用4替换
cout<
<
"替换后的values数组元素为:";
for(int i=0;
i<
values.size();
i++)
cout<
<
values[i]<
<
" ";
cout<
<
\\n;
values.swap(values1);
//交换数组的元素,前提是这两个数组的大小一样
cout<
<
"交换后values数组的结果为:";
for(int j=0;
j<
values.size();
j++)
cout<
<
values[j]<
<
" ";
return 0;
//auto表示的是任一类型的指针
测试结果如下:
(2)vector<
T>
容器
基本操作表如下:
(1)push_back()和 emplace_back() 均可以实现在尾部添加一个元素的功能,但不同的是,前者是要先创建元素,然后再将该元素复制拷贝到容器中,后者则是省去了复制和移动的过程直接将元素放入容器。
代码解释如下:
(2)insert()和emplace()均可以在容器中插入元素,因为insert()需要进过复制环节,所以emplace()的效率更高
#include<
iostream>
#include<
vector>
//引入头文件
using namespace std;
int main()
vector<
int >
values1,2;
vector<
int >
values1
推荐阅读
- CentOS8下使用Apache Httpd创建源服务
- Scala中特质与抽象类有什么区别()
- 同步和异步时序电路之间的差异
- 二叉树的奇数级和偶数级节点之和之间的差
- 算法题(K个最大偶数和奇数数组元素之和之间的差)
- 结构化,半结构化和非结构化数据之间的差异
- 停止和等待,GoBackN和选择性重复之间的区别
- SQL和NoSQL之间有什么区别(有哪些区别?)
- Spring和Spring Boot之间有什么区别()