C++笔记(12) 标准模板库STL
STL提供了一组表示容器、迭代器、函数、函数对象和算法的模板。STL不是面向对象的编程,而是一种不同的编程模式——泛型编程。
- 容器:与数组类似的单元,可以存储若干个值,存储的值的类型相同;
- 算法:完成特定任务(如对数组进行排序或在链表中查找特定值)的处方;
- 迭代器:能供用来遍历容器的对象,与能够遍历数组的指针类似,是广义指针;
- 函数对象:类似于函数的对象,可以是类对象或函数指针(包括函数名,因为函数名被用作指针)。
容器
通用容器分为3类:顺序容器、关联容器、容器适配器。
1. 顺序容器
(1)vector:数组的一种类表示,提供自动内存管理功能,可以动态地改变对象长度;
提供对元素的随机访问,在尾部之外的位置插入或者删除元素可能很慢。
(2)deque:双端列表,支持随机访问,从deque对象开始位置插入和删除元素的时间固定。
(3)list:双向链表,可以双向遍历列表,任意位置插入和删除元素时间固定,不支持数组表示法和随机访问。
(4)array:在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。(C++11标准新加)
在使用上,它比普通数组更安全(原因后续会讲),且效率并没有因此变差。
array 容器的大小是固定的,因此无法借由增加或移除元素而改变其大小,它只允许访问或者替换存储的元素。
(5)forward_list : 单向链表。只支持单向顺序访问。在链表的任何位置进行插入、删除操作都很快。(C++11标准新加)
2. 关联容器
关联容器将值与键关联在一起,并使用键来查找值。关联容器的优点在于,它提供了对元素的快速访问。与序列相似,关联容器也允许插入新元素,但不能指定元素的插入位置。原因是关联容器通常有用于确定数据放置位置的算法,以便能够快速检索信息。
关联容器通常是使用树实现的。树是一种数据结构,其根节点链接到一个或两个节点,而这些节点又链接到一个或两个节点,从而形成分支结构,与链表相比,树的查找速度更快。
(1)set:值和键的类型相同,键是唯一的,值就是键。
(2)multiset:类似于set,只是可能又多个值的键相同。
(3)map:键与值类型不同,键是唯一的,每个键只对应一个值。
(4)multimap:类似于map,只是一个键可以和多个值相关联。
//由于此处初始化时指示了对键进行排序的比较函数,因此下面的set_union也需要加,不然会异常
#include <set>
#include <string>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;
int main() { set<int,greater<int>> A{ 1,2,3,4,5,6,9,9 };
set<int, greater<int>> B{ 6,5,4,3,2,1 };//由于此处初始化时指示了对键进行排序的比较函数,因此下面的set_union也需要加,不然会异常 ostream_iterator<int, char> out(cout, " ");
cout << "set A:";
copy(A.begin(), A.end(), out);
cout << "\nset B:";
copy(B.begin(), B.end(), out);
cout << "\n" << "Union of A and B:";
set_union(begin(A), A.end(), B.begin(), B.end(),out, greater<int>());
return 0;
}
无序关联容器
(1)unordered_map : 用哈希函数组织的map
(2)unordered_set : 用哈希函数组织的set
(3)unordered_multimap : 哈希组织的map;关键字可以重复出现
(4)unordered_multiset : 哈希组织的set;关键字可以重复出现
从上面的容器名称可以看出:允许重复关键字的容器名字都包含multi;而使用哈希技术的容器名字都以unordered开头。
3. 适配器
容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。
(1)queue:封装了 deque 容器,不允许随机访问队列元素,不允许遍历队列。可以添加元素到队尾push(),删除队首pop(),size(),以及empty();
(2)priority_queue:封装了 vector 容器,默认实现的是一个会对元素排序,从而保证最大元素总在队列最前面的队列。
(3)stack:封装了 deque 容器,默认实现的是一个后入先出(Last-In-First-Out,LIFO)的压入栈。
容器操作
size()——返回容器中元素数目
swap()——交换两个容器的内容
begin()——返回一个指向容器中第一个元素的迭代器
end()——返回一个表示超多容器尾的迭代器
push_back()——将元素添加到矢量末尾
erase()——删除矢量中给定区间的元素(函数接受两个迭代器参数,第一个迭代器指向区间的起始处,第二个迭代器位于区间终止处的后一个位置)
insert()——在给定区间插入元素(函数接受3个迭代器参数,第一个参数指定了新元素的插入位置,第二个和第三个迭代器参数定义了被插入区间,该区间是另一个容器的一部分)
迭代器
什么是迭代器?它是一个广义指针,也可以是一个对其执行类似指针的操作——如解除引用operator*()和递增operator++()的对象。通过将指针广义化为迭代器,让STL能够为各种不同的容器类提供统一的接口。每个容器类都定义了一个合适的迭代器,该迭代器的类型是一个名为iterator的typedef,其作用域为整个类。比如:
vector<double>::iterator pd;
vector<double> scores;
pd = scores.begin();//使pd指向第一个元素
*pd = 22.3;//解除引用并赋值
++pd;//使pd指向下一个元素
算法
算法用来处理群集内的元素,可以出于不同目的搜寻、排序、修改、使用那些元素。所有容器的迭代器都提供一致的接口,通过迭代器的协助,算法程序可以用于任意容器。常见的算法如下:
- for_each()——可以代替for循环
例如:
vector<int>::iterator pr;
for (pr = a.begin(); pr != a.end(); pr++) {
show(*pr);
}
可以替换为:
for_each(a.begin(), a.end(), show);
- random_shuffle()——随机排列区间中的元素
函数接受两个指定区间的迭代器参数,并随机排列该区间中的元素
random_shuffle(a.begin(), a.end());
- sort()——排序
第一个版本,接受两个定义区间的迭代器参数,并使用(为存储在容器中的类型元素定义的)<运算符,对区间中的元素进行操作。
如果容器元素是自定义的对象,要使用sort(),必须定义该对象的operate<()函数,例如:
class Person {
public:
Person(int a, int h) :age(a), height(h) {};
int age;
int height;
};
bool operator<(const Person& p1, const Person& p2) {
if (p1.age < p2.age)
return true;
else if (p1.age == p2.age && p1.height < p2.height)
return true;
else
return false;
}
排序:
Person p1(11, 150); Person p2(12, 160); Person p3(11, 160);
vector<Person> ps({ p1,p2,p3 });
sort(ps.begin(), ps.end());
上面是以全局函数的形式实现对 < 运算符的重载,还可以使用成员函数或者友元函数的形式实现。其中,当以成员函数的方式重载 < 运算符时,该成员函数必须声明为 const 类型,且参数也必须为 const 类型:
bool operator<(const Person& temp) {
if (this->age < temp.age)
return true;
else if (this->age == temp.age && this->height < temp.height)
return true;
else
return false;
}
同样,如果以友元函数的方式重载 < 运算符时,要求参数必须使用 const 修饰:
//类中友元函数的定义
friend bool operator <(const myString &a, const myString &b); //类外部友元函数的具体实现
bool operator <(const myString &stra, const myString &strb) {
//以字符串的长度为标准比较大小
return stra.str.length() < strb.str.length();
}
第二个版本,如果不是想升序,想降序,或者其他的排序方法,就定义一个函数:
bool fun(const Person& p1, const Person& p2) {
...
}
sort(ps.begin(), ps.end(), fun);
用lamda表达式后:
sort(v.begin(), v.end(), [](const int& a, const int& b) { return a > b; });
函数对象(仿函数)
一般来说,如果我们列出一个对象,而它的后面又跟有由括号包裹的参数列表,就像f(arg1, arg2, ...)
,这个对象就被称为函数对象。
注意:函数对象使一个类,不是一个函数,函数对象重载了“()”操作符使得它可以像函数一样调用。比如:
class Add
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
Add add; // 定义函数对象
cout << add(3, 2); // 5
函数指针版本为:
int AddFunc(int a, int b)
{
return a + b;
}
typedef int (*Add) (int a, int b);
Add add = &AddFunc;
cout << add(3,2);
既然C++函数对象与函数指针在使用方式上没什么区别,那为什么要用函数对象呢?很简单,函数对象可以携带附加数据,而指针就不行了。比如:
class less
{
public :
less(int num) : n(num) {}
bool operator()(int value)
{
return value < n;
}
private :
int n;
};
使用时:
const int SIZE = 5;
int array[SIZE] = { 50, 30, 9, 7, 20};
// 找到小于数组array中小于10的第一个数的位置
int * pa = std::find_if(array, array + SIZE, less(10));
// pa 指向 9 的位置
// 找到小于数组array中小于40的第一个数的位置
int * pb = std::find_if(array, array + SIZE, less(40));
// pb 指向 30 的位置
参考文献:
1. 《C++ Primer Plus》第16章
3. 干货分享:什么是C++STL?掌握C++ STL的核心很重要!
C++笔记(12) 标准模板库STL的更多相关文章
- 标准模板库(STL)学习探究之stack
标准模板库(STL)学习探究之stack queue priority_queue list map/multimap dequeue string
- 标准模板库(STL)学习探究之vector容器
标准模板库(STL)学习探究之vector容器 C++ Vectors vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被 ...
- C++ 标准模板库(STL)
C++ 标准模板库(STL)C++ STL (Standard Template Library标准模板库) 是通用类模板和算法的集合,它提供给程序员一些标准的数据结构的实现如 queues(队列), ...
- STL学习系列之一——标准模板库STL介绍
库是一系列程序组件的集合,他们可以在不同的程序中重复使用.C++语言按照传统的习惯,提供了由各种各样的函数组成的库,用于完成诸如输入/输出.数学计算等功能. 1. STL介绍 标准模板库STL是当今每 ...
- 标准模板库--STL
标准模板库STL 1.泛型程序设计 C++ 语言的核心优势之一就是便于软件的重用 C++中有两个方面体现重用: 1.面向对象的思想:继承和多态,标准类库 2.泛型程序设计(generic progra ...
- C++的标准模板库STL中实现的数据结构之顺序表vector的分析与使用
摘要 本文主要借助对C++的标准模板库STL中实现的数据结构的学习和使用来加深对数据结构的理解.即联系数据结构的理论分析和详细的应用实现(STL),本文是系列总结的第一篇,主要针对线性表中的顺序表(动 ...
- 实验8 标准模板库STL
一.实验目的与要求: 了解标准模板库STL中的容器.迭代器.函数对象和算法等基本概念. 掌握STL,并能应用STL解决实际问题. 二.实验过程: 完成实验8标准模板库STL中练习题,见:http:// ...
- C++的标准模板库STL中实现的数据结构之链表std::list的分析与使用
摘要 本文主要借助对C++的标准模板库STL中实现的数据结构的学习和使用来加深对数据结构的理解,即联系数据结构的理论分析和详细的应用实现(STL),本文是系列总结的第二篇.主要针对线性表中的链表 ST ...
- C++ 标准模板库STL 队列 queue 使用方法与应用介绍
C++ 标准模板库STL 队列 queue 使用方法与应用介绍 queue queue模板类的定义在<queue>头文件中. 与stack模板类很相似,queue模板类也需要两个模板参数, ...
- 【c++】标准模板库STL入门简介与常见用法
一.STL简介 1.什么是STL STL(Standard Template Library)标准模板库,主要由容器.迭代器.算法.函数对象.内存分配器和适配器六大部分组成.STL已是标准C++的一部 ...
随机推荐
- 华为云CodeArts IDE For Python 快速使用指南
本文分享自华为云社区<华为云CodeArts IDE For Python 快速使用指南>,作者:为云PaaS服务小智. CodeArts IDE 带有 Python 扩展,为 Pytho ...
- 如何将 ASP.NET Core MVC 项目的视图分离到另一个项目
如何将 ASP.NET Core MVC 项目的视图分离到另一个项目 在当下这个年代 SPA 已是主流,人们早已忘记了 MVC 以及 Razor 的故事.但是在某些场景下 SSR 还是有意想不到效果. ...
- HarmonyOS NEXT应用开发案例——列表编辑实现
介绍 本示例介绍用过使用ListItem组件属性swipeAction实现列表左滑编辑效果的功能. 该场景多用于待办事项管理.文件管理.备忘录的记录管理等. 效果图预览 使用说明: 点击添加按钮,选择 ...
- 通过 MSE 实现基于Apache APISIX的全链路灰度
简介: 无论是微服务网关还是微服务本身都需要识别流量,根据治理规则做出动态决策.当服务版本发生变化时,这个调用链路的转发也会实时改变.相比于利用机器搭建的灰度环境,这种方案不仅可以节省大量的机器成本和 ...
- Nacos 2.0 性能提升十倍,贡献者 80% 以上来自阿里之外
简介: 3 月 20 日,Nacos 2.0 正式发布.Nacos 是阿里巴巴在 2018 年开源的一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台,也可以理解为微服务的注册中心 + 配 ...
- Snowflake如日中天是否代表Hadoop已死?大数据体系到底是什么?
简介: 本文作者关涛是大数据系统领域的资深专家,在微软(互联网/Azure云事业群)和阿里巴巴(阿里云)经历了大数据发展20年过程中的后15年.本文试从系统架构的角度,就大数据架构热点,每条技术线的 ...
- 快速上手 Serverless | 入门第一课
简介: 本文从云计算抛砖引玉,详解 Serverless 的典型应用场景和一些产品介绍. 一. 从云计算到 Serverless 自世界上第一台通用计算机 ENIAC (图左)诞生以来,计算机科学与技 ...
- [FAQ] swagger-php 支持 Authorization Bearer token 校验的用法
@OA\SecurityScheme 可以是 Controller 层面也可以是 Action 层面. 类型 type="apiKey". in="header" ...
- [PHP] 浅谈 Laravel 三大验证方式的区别, auth:api, passport, auth:airlock
auth:api 最先出来,提供了最简单和最实用的方式进行 api 身份校验. 关于它的含义和用法你可以参考以下两篇: 浅谈 Laravel Authentication 的 auth:api 浅谈 ...
- dotnet 通过 DockerfileContext 解决项目放在里层文件夹导致 VisualStudio 构建失败
本文告诉大家,如何解决 csproj 项目文件放入到里层的文件夹,不放在 sln 所在文件夹的第一层子文件夹,导致 VisualStudio 2022 在构建 docker 映像提示找不到文件的问题 ...