七、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() 返回一个起始位置/末端下一个位置的iterator
  • push_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)元素
vectorlist之间的差别
  • 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;
}

迭代器的分类

分类的依据:迭代器的移动特性,与内存的连续性也有关。

部分容器是没有提供迭代器的stackqueue,因为它们遵循后进先出和先进先出的规则。

  • 输出型迭代器: (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; 继承自前向迭代器
    • 能力: 向前和向后读取
    • 提供者: listset、 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
Created with Raphaël 2.2.0输入型迭代器前向迭代器双向迭代器随机访问迭代器
验证迭代器类型的代码
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的阉割版)

  1. stack:堆栈
  2. 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标准模板库大局观相关推荐

  1. 19.1 C++STL标准模板库大局观-STL总述、发展史、组成与数据结构谈

    19.1 C++STL标准模板库大局观-STL总述.发展史.组成与数据结构谈 19.2 C++STL标准模板库大局观-容器分类与array.vector容器精解 19.3 C++STL标准模板库大局观 ...

  2. 19.3 C++STL标准模板库大局观-容器的说明和简单应用例续

    19.1 C++STL标准模板库大局观-STL总述.发展史.组成与数据结构谈 19.2 C++STL标准模板库大局观-容器分类与array.vector容器精解 19.3 C++STL标准模板库大局观 ...

  3. 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 ...

  4. 信息学奥赛中的STL(标准模板库)--2022.09.30

    1.信息学奥赛一本通 第5版 第8章 C++实用技巧与模版库(6节) 第一节  排序算法 第二节 运算符重载 第三节  字符串(string) 第四节 FIFO队列和优先队列 第五节  动态数组 第六 ...

  5. 7精通 S T L(C++标准模板库)-王桂林-专题视频课程

    <7>精通 S T L(C++标准模板库)-332人已学习 课程介绍         STL是Standard Template Library的简称,中文名标准模板库,是集数据结构与算法 ...

  6. 补8-5日复习内容 STL 标准模板库的容器

    //有关 STL 标准模板库的函数 /* string 的 */ /* #include <iostream> #include <string> #include <w ...

  7. stl标准模板库_C ++标准模板库(STL)中的array :: fill()

    stl标准模板库 fill() is a member function of "array container", which sets a given value to all ...

  8. stl标准模板库_C ++标准模板库(STL)中的数组及其常用功能

    stl标准模板库 "array" is a container in C++ STL, which has fixed size, which is defined in &quo ...

  9. C++的STL标准模板库思维导图

    STL标准模板库思维导图 C++ 语言的核心优势之一就是便于软件的重用.C++ 中有两个方面体现重用: 一是面向对象的继承和多态机制: 二是通过模板的概念实现了对泛型程序设计的支持. C++ 的标准模 ...

最新文章

  1. java写事物提交_fabric-sdk-java 提交事务
  2. 打通Devops的Scrum敏捷工具
  3. “CEPH浅析”系列之八——小结
  4. Win10如何找出占用硬盘空间大的文件及怎么删除
  5. python如何输入和输出_输入和输出
  6. 阻止xap文件在浏览器中缓存
  7. python apscheduler 动态_基于Flask-APScheduler实现添加动态定时任务
  8. js实现treeview 级联修改状态
  9. grep配置颜色显示
  10. Vivado 2019.1下载与安装
  11. 局域网ip扫描工具_中科院网络工程师网络安全视频教程10端口扫描
  12. 频繁gc是什么意思_经常听到的期货黄金gc是什么意思?
  13. 如何使用LaTeX完成一篇论文的基本排版
  14. windows下使用route添加路由
  15. 商场三十六计——第8计 “暗渡陈仓”
  16. 机器人与视觉,基于坐标系的运动偏移
  17. TensorFlow 手写实现卷积神经网络CNN
  18. 在Android Studio中隐藏APP的标题栏
  19. http://www.makepic.com/print.php,在线制作印章
  20. 火狐浏览器Firefox上DownThemAll插件

热门文章

  1. [论文学习]:Mean Curvature Skeletons
  2. 工业智能相机镜头选型参考
  3. python中os.path.isfile函数
  4. 【Luat-air551G】5 用lvgl显示GGA数据
  5. OpenCV摄像头-录屏
  6. 【NISP一级】3.1 计算机网络和网络设备
  7. 装修半包与全包的区别
  8. Android写入联系人
  9. 解析二维码如何批量解析二维码内容
  10. Docker安装Oracle_11g数据库并配置