C++入门到精通 ——第七章 STL标准模板库大局观
七、STL标准模板库大局观
Author: XFFer_
先分享一本 《C++ 标准库 第二版》 ,望在STL的道路上从入门到放弃!(开玩笑的啦,愈行愈远~)
链接: https://pan.baidu.com/s/1nna7m5F11poNNvEi2ydOyQ
提取码: otld
文章目录
- 七、STL标准模板库大局观
- 01 STL总述、发展史、组成,数据结构谈
- 几个概念
- 推荐书籍
- STL发展史和各个版本
- STL的组成部分
- 02 容器分类、array、vector容器精解
- 容器的分类
- 容器的说明
- array
- vector
- 03 容器的说明和简单应用例续
- deque和stack
- list:双向链表
- `vector` 和 `list`之间的差别
- 其他
- 04 分配器概述、使用,工作原理说
- 分配器概述&分配器的使用
- 05 迭代器的概念和分类
- 迭代器基本概念
- 迭代器的分类
- 族谱smirk.jpg
- 验证迭代器类型的代码
- 06 算法概述、内部处理、使用范例
- 算法概述
- 算法内部的一些处理
- 一些典型算法使用范例
- `for_each`
- 源码
- 使用方法
- `find`
- `find_if`
- `sort`
- 07 函数对象回顾、系统函数对象及范例
- 函数对象(function object)、仿函数回顾(functors)
- 标准库中定义的函数对象[functional](https://zh.cppreference.com/w/cpp/header/functional)->[第八章 未归类知识点](https://blog.csdn.net/qq_44455588/article/details/104474038)
- 标准库中定义的函数对象范例
- 08 适配器概念、分类、范例及总结
- 容器适配器
- 算法适配器
- 迭代器适配器
01 STL总述、发展史、组成,数据结构谈
1 几个概念
2 推荐书籍
3 算法和数据结构浅谈
4 STL发展史和各个版本
5 标准库的使用说明
6 STL的组成部分
几个概念
- C++标准库:C++ Standard Library
- 标准模板库:Standard Template Library(STL)
- 泛型编程:Generic Programming
推荐书籍
《STL源码剖析》
链接: https://pan.baidu.com/s/1apswforzS6dp5-3S05SKeA
提取码: gk0l
《C++标准库》
链接: https://pan.baidu.com/s/1nna7m5F11poNNvEi2ydOyQ
提取码: otld
STL发展史和各个版本
- HP STL: 惠普STL,是所有STL实现版本的始祖
- SGI STL: 参考惠普STL实现的,Linux下的GNU C++(gccc, g++)使用
- P.J.Plauger STL: Visual C++使用
STL的组成部分
- 容器: vector、list、map
- 迭代器: 用于遍历或者访问容器中的元素
- 算法: (函数),用来实现一些功能,search、sort、copy…
- 分配器
- 其他: 适配器、仿函数等
02 容器分类、array、vector容器精解
1 容器的分类
2 容器的说明
array
vector
容器的分类
顺序容器(Sequence Container):能控制插入位置
array
vector
deque
list
forward_list
关联容器(Associative Container):元素是 “键值对”,适合用来查找。能够控制插入内容,但不能控制插入位置
set
multiset
map
multimap
无序容器(Unordered Container):C++11推出,元素位置不重要,重要的是否存在该元素
unordered_set
unordered_multiset
unordered_map
unordered_multimap
容器的说明
array
内存空间是连续的,大小是固定的
使用形式: array<type_name, N> value_name
可以就当做数组来用。
vector
vector有一个“空间”的概念,容器内存是紧挨着的,故vector从末尾添加元素push_back
时,如果容器空间不足就会重新寻找一个足够大的内存存放对象。
容器中有多少个元素可以用size()
来看,有多少空间可以用capacity()
,capacity≥sizecapacity\geq sizecapacity≥size。
vector基础知识在前面的章节有所提到。
当erase(iter)
容器内部一个元素时,处理是比较高效的,其后的元素地址都会顺次移动,仍然是连续的内存。
当insert(iter, value)
插入一个元素时,代价很大,会造成其后的元素重新构造,导致降低效率。
故可以使用reserve(size)
提前留出空间capacity,可以大量提高程序的预留效率。
03 容器的说明和简单应用例续
1 deque和stack
2 queue
3 list
4 其他forward_list
set/map
unordered_set、unordered_multiset等
deque和stack
deque
:双端数列(double-ended queue) ,分段连续内存,以分段数组的形式存储。
#include <queue>deque<type_name> value_name;value_name.push_front(); //从队列的前面插入
value_name.push_back(); //从队列的后面插入
value_name.pop_front(); //从队列的前面删除
value_name.push_back(); //从队列的前面删除
stack
:堆栈/栈,只有一个开口,后进先出,后进会放在栈顶,先进会压在栈底,不支持从总结插入/删除数据。deque实际上是包含着stack的功能的。
queue
:普通队列 先进先出
list:双向链表
不需要内存是连续的,查找效率不突出,但是在任意位置插入和删除元素非常迅速。
begin()/end()
返回一个起始位置/末端下一个位置的iteratorpush_back()
push_front()
在末端/头部插入元素empty()
判断是否为空resize()
将list长度改为容纳n个元素clear()
清空front()
back()
获取头部/末端元素,不能为空pop_front()
pop_back()
从头部/末端删除一个元素insert()
插入一个或多个元素insert(iter, value)
insert(iter, number_of_v, value)
erase()
删除元素/区间内(用iter)元素
vector
和 list
之间的差别
- vector类似于数组,内存空间是连续的,list双线链表,内存空间并不连续
- vector从中间或者开头插入元素效率比较低;但是list插入元素效率非常高
- vector当内存不足时,会重新找一块内存,对原来的内存对象做析构,再在新的内存重新构造
- vector能够高效的随机存取,而list做不到。vector可以通过迭代器,而list需要沿着链表一个个找,直到找到所需的元素
这里vector的细节知识可以参考C++中list用法详解,本文只是简单的总述STL标准库。
其他
forward_list
:单向链表(受限list)set / map
:关联容器。内部实现的数据结构多为红黑树。这些容器没有push_front/back
的操作,因为内存并不是规律的- 常用操作↓
#include <map>
#include <functional>
#include <string>map<int, string> mymap;
map<string, function<int(int)>> mymap2; //可以存入函数类型为int(int)的函数//插入的五种方式
mymap.insert(pair<int, string>(000, "first"));mymap.insert(map<int, string>::value_type(000, "first"));mymap.insert(std::make_pair(000, "first"));mymap.insert({000, "first"});mymap[000] = "first"; //相同key可覆盖//find查找元素,返回迭代器指向当前查找元素的位置,否则返回map::end()位置即最后一个元素后(空)
auto iter = mymap.find(001);if (iter != mymap.end())cout << "find it!" << endl;
elsecout << "do not find" << endl;//删除与清空元素
auto iter = mymap.begin();
mymap.erase(iter); //用迭代器删除mymap.erase(000); //用键删除mymap.erase(mymap.begin(), mymap.end()); //范围删除,等同于mymap.clear();
快捷键补充
shift+Home
取光标前本行内容
shift+End
取光标后本行内容
04 分配器概述、使用,工作原理说
1 分配器概述
2 分配器的使用
3 其他的分配器及原理说
4 自定义分配器
这节很水smirk~,因为我菜所以没有去详细了解分配器
分配器概述&分配器的使用
内存分配器,通过测试没有采用内存池的技术
allocate(num)
是分配器内的重要函数,用来分配内存,这里的num值几个对象而不是字节数deallocate(point, num)
用于释放函数,point是指向分配内存的指针
↓图为侯捷老师讲授分配器时使用过的
这里可以参考学习资料集聚地—小破站侯捷老师的STL源码剖析。
05 迭代器的概念和分类
1 迭代器基本概念
2 迭代器的分类
迭代器基本概念
迭代器用来表现容器中的某一个位置,紧密依赖于容器,是一个“可遍历STL容器全部或部分内容”的对象(行为类似于指针)。
//示例
vector<int> v = {1, 2, 3};
for (auto iter = v.begin(); iter != v.end(); iter++)
{cout << *iter << endl;
}
迭代器的分类
分类的依据:迭代器的移动特性,与内存的连续性也有关。
部分容器是没有提供迭代器的stack
、queue
,因为它们遵循后进先出和先进先出的规则。
- 输出型迭代器: (Output iterator)
struct output_iterator_tag;
- 能力: 向前写入
- 提供者: ostream 、inserter
*iter = val
将val写☞迭代器所指位置++iter
向前步进,返回新位置iter++
向前步进,返回旧位置TYPE(iter)
复制迭代器(copy构造函数)
- 输入型迭代器: (Input iterator)
struct input_iterator_tag;
- 能力: 向前读取一次
- 提供者: Istream
*iter
读取实际元素iter -> member
读取实际元素的成员++iter
向前步进,返回新位置iter++
向前步进,返回旧位置iter1 == iter2
判断是否相等iter1 != iter2
判断是否不等TYPE(iter)
复制迭代器(copy构造函数)
- 前向迭代器: (Forward iterator)
struct forward_iterator_tag;
继承自输入型迭代器- 能力: 向前读取
- 提供者: Forward list、 unordered containers
- 继承输入迭代器所有操作
iter1 == iter2
对迭代器赋值(assign)
- 双向迭代器: (Bidirectional iterator)
struct bidirectional_iterator_tag;
继承自前向迭代器- 能力: 向前和向后读取
- 提供者: list 、set、 multiset 、map、 multimap
--iter
步退,返回新位置iter--
步退,返回旧位置
- 随机访问迭代器: (random-access iterator)
struct random_access_iterator_tag;
继承自双向迭代器- 能力: 以随机访问方式读取
- 提供者: Array、 vector 、deque 、string 、C-style array
- 增加了随机访问能力,可以计算距离增减某个偏移量(内存是连续的)
iter[n]
返回索引位置为n的元素iter+=n
前进n个元素iter-=n
回退n个元素iter+n
返回iter之后的第n个元素n+iter
返回iter之后的第n个元素iter-n
返回iter之前的第n个元素iter1-iter2
返回iter1和iter2之间的距离iter1<iter2
判断iter1是否在iter2之前iter1>iter2
判断iter1是否在iter2之后iter1<=iter2
判断iter1是否不在iter2之后iter1>=iter2
判断iter1是否不在iter2之前
族谱smirk.jpg
验证迭代器类型的代码
void _display_category(random_access_iterator_tag mytag)
{cout << "random_access_iterator_tag" << endl;
}
void _display_category(bidirectional_iterator_tag mytag)
{cout << "bidirectional_iterator_tag" << endl;
}
void _display_category(forward_iterator_tag mytag)
{cout << "forward_iterator_tag " << endl;
}
void _display_category(forward_iterator_tag mytag)
{cout << "forward_iterator_tag " << endl;
}
void _display_category(output_iterator_tag mytag)
{cout << "output_iterator_tag " << endl;
}
void _display_category(input_iterator_tag mytag)
{cout << "input_iterator_tag " << endl;
}template<typename T>
void display_category(T ite) {cout << "----------begin----------" << endl;//整个这个类型叫 过滤器(萃取机),用来获取T迭代器类型的种类typename iterator_traits<T>::iterator_category cagy;_display_category(cagy); //编译器挑选一个适合的重载函数,cagy就是迭代器的种类cout << "typeid(ite).name() = " << typeid(ite).name() << endl;cout << "----------end----------" << endl;
}display_category(vector<int>::iterator()); //这样就OK了
06 算法概述、内部处理、使用范例
1 算法概述
2 算法内部一些处理
3 一些典型的算法使用范例for_each
find
find_if
sort
算法概述
算法内部的一些处理
算法会根据传递进来的迭代器来分析出迭代器种类,不同种类的迭代器,算法会有不同的处理。
一些典型算法使用范例
#include <algorithm>
for_each
源码
template<class _InIt,class _Fn> inline_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func){ // perform function for each element [_First, _Last)_DEBUG_RANGE(_First, _Last);auto _UFirst = _Unchecked(_First);const auto _ULast = _Unchecked(_Last);for (; _UFirst != _ULast; ++_UFirst){_Func(*_UFirst);}return (_Func);}
通过源码可以清晰的看出for_each有三个参数,前两个参数用来确定一个迭代区间,第三个参数则是操作方式,lambda,函数对象或者普通函数。
使用方法
void func(int i)
{cout << i << endl;
}
int main()
{vector<int> myvector = { 10, 20, 30, 40, 50 };for_each(myvector.begin(), myvector.end(), func);//for_each每次迭代对象将得到的值调用第三个参数的函数return 0;
}
find
这里使用的是泛化模板的find,当容器有特有的.find
成员时,建议使用特有的效率更高。返回值都是 iterator
。
vector<int> myvector = { 10, 20, 30, 40, 50 };
vector<int>::iterator finditer = find(myvector.begin(), myvector.end(), 400);if (finditer != myvector.end()) //!=后的使用第二个参数
{//find it!
}
else
{//can not find
}
find_if
前两个参数确定一个查找区间,第三个参数返回值是一个bool。
auto result = (myvector.begin(), myvector.end(), [](int vel){if (val > 10)return true; //停止遍历
return false;
}); //lambda表达式也是一个可调用对象if (result != myvector.end())cout << "找到了" << endl;
elsecout << "没找到" << endl;
sort
当第三个参数缺省时,从小到大排序,第三个参数返回值是bool。
bool func(int i, int j)
{return i < j;
}
auto result = sort(myvector.begin(), myvector.end(), func); //从小到大bool func(int i, int j)
{return i > j;
}
auto result = sort(myvector.begin(), myvector.end(), func); //从大到小
对list
而言不能用标准库的sort(),它有自己的sort(),参数表传入返回值bool的比较规则。
07 函数对象回顾、系统函数对象及范例
1 函数对象、仿函数回顾
2 标准库中定义的函数对象
3 标准库中定义的函数对象范例
函数对象(function object)、仿函数回顾(functors)
- 函数:
void func(...) { ... }
- 可调用对象:
class A { void operator() (...) { ... } };
- lambda表达式 :
[](...) { ... };
标准库中定义的函数对象functional->第八章 未归类知识点
#include <functional>
标准库中定义的函数对象范例
vector<int> myvector = { 150, 20, 3, 98, 50 };
auto result = sort(myvector.begin(), myvector.end(), greater<int>()); //从大到小
greater<typename>()
就是一个仿函数。
08 适配器概念、分类、范例及总结
1 适配器基本概念
2 容器适配器
3 算法适配器
4 迭代器适配器
容器适配器
适配器像一个转接口。
主要讲一下:(它俩都是deque的阉割版)
stack
:堆栈queue
:队列
实际上在这里我们就把它们看做适配器而不是容器。
算法适配器
std::bind
绑定器(第八章 未归类知识点)
vector<int> myvector = { 150, 20, 3, 20, 50 };
bool func(int tmp)
{return tmp > 40;
}int result = count(myvector.begin(), myvector.end(), 20); //return 2int result = count_if(myvector.begin(),myvector.end(), func); //return 2
如果想用less<typename>(value1, value2)
这个仿函数代替掉自己写的func,就需要用到bind
绑定器。
auto contrast = bind(less<int>(), 40, placeholders::_1)//less<int>()第一个参数绑定为40, 第二个参数是在被调用时传入的第一个参数
int result = count_if(myvector.begin(), myvector.end(), contrast);
迭代器适配器
reverse_iterator
在这里归为适配器
前文已经提到。
C++入门到精通 ——第七章 STL标准模板库大局观相关推荐
- 19.1 C++STL标准模板库大局观-STL总述、发展史、组成与数据结构谈
19.1 C++STL标准模板库大局观-STL总述.发展史.组成与数据结构谈 19.2 C++STL标准模板库大局观-容器分类与array.vector容器精解 19.3 C++STL标准模板库大局观 ...
- 19.3 C++STL标准模板库大局观-容器的说明和简单应用例续
19.1 C++STL标准模板库大局观-STL总述.发展史.组成与数据结构谈 19.2 C++STL标准模板库大局观-容器分类与array.vector容器精解 19.3 C++STL标准模板库大局观 ...
- C++ STL 标准模板库介绍与入门
目录 1.概述 1.1.C++ 标准库 1.2.Boost库 2.STL 版本 2.1.HP 原始版本 2.2.P. J. 实现版本 2.3.RW 实现版本 2.4.SGI 实现版本 2.5.STLp ...
- 信息学奥赛中的STL(标准模板库)--2022.09.30
1.信息学奥赛一本通 第5版 第8章 C++实用技巧与模版库(6节) 第一节 排序算法 第二节 运算符重载 第三节 字符串(string) 第四节 FIFO队列和优先队列 第五节 动态数组 第六 ...
- 7精通 S T L(C++标准模板库)-王桂林-专题视频课程
<7>精通 S T L(C++标准模板库)-332人已学习 课程介绍 STL是Standard Template Library的简称,中文名标准模板库,是集数据结构与算法 ...
- 补8-5日复习内容 STL 标准模板库的容器
//有关 STL 标准模板库的函数 /* string 的 */ /* #include <iostream> #include <string> #include <w ...
- stl标准模板库_C ++标准模板库(STL)中的array :: fill()
stl标准模板库 fill() is a member function of "array container", which sets a given value to all ...
- stl标准模板库_C ++标准模板库(STL)中的数组及其常用功能
stl标准模板库 "array" is a container in C++ STL, which has fixed size, which is defined in &quo ...
- C++的STL标准模板库思维导图
STL标准模板库思维导图 C++ 语言的核心优势之一就是便于软件的重用.C++ 中有两个方面体现重用: 一是面向对象的继承和多态机制: 二是通过模板的概念实现了对泛型程序设计的支持. C++ 的标准模 ...
最新文章
- java写事物提交_fabric-sdk-java 提交事务
- 打通Devops的Scrum敏捷工具
- “CEPH浅析”系列之八——小结
- Win10如何找出占用硬盘空间大的文件及怎么删除
- python如何输入和输出_输入和输出
- 阻止xap文件在浏览器中缓存
- python apscheduler 动态_基于Flask-APScheduler实现添加动态定时任务
- js实现treeview 级联修改状态
- grep配置颜色显示
- Vivado 2019.1下载与安装
- 局域网ip扫描工具_中科院网络工程师网络安全视频教程10端口扫描
- 频繁gc是什么意思_经常听到的期货黄金gc是什么意思?
- 如何使用LaTeX完成一篇论文的基本排版
- windows下使用route添加路由
- 商场三十六计——第8计 “暗渡陈仓”
- 机器人与视觉,基于坐标系的运动偏移
- TensorFlow 手写实现卷积神经网络CNN
- 在Android Studio中隐藏APP的标题栏
- http://www.makepic.com/print.php,在线制作印章
- 火狐浏览器Firefox上DownThemAll插件