STL
- STL:Standard Template Library,标准模板库,C++ 标准库一部分,基于模板实现,复用数据结构与算法代码
STL 六大组件
- 容器 container:各类数据结构,存放数据(vector、list、map...)
- 算法 algorithm:通用算法,排序、查找、拷贝等
- 迭代器 iterator :容器和算法之间的桥梁,类似指针,用来遍历容器元素
- 仿函数 functor :重载
()的类,行为像函数,给算法提供自定义策略- 适配器 adapter:包装其他组件,修改接口(stack、queue 就是容器适配器)
- 空间配置器 allocator:负责内存空间分配、释放、管理
组件交互关系
容器依靠空间配置器申请内存
算法通过迭代器访问容器里的数据
仿函数给算法提供自定义策略
适配器用来修饰容器 / 仿函数 / 迭代器接口
三大核心组件
- 三大核心:容器、算法、迭代器
容器
分为 序列式容器 和 关联式容器
序列式容器 :元素位置由插入顺序 决定,元素是有序排列,但值不一定有序
1)vector、deque、list、forward_list关联式容器 :容器内部自带排序规则,元素位置由元素值 / 键值 决定,自动有序
1)map、set、multimap、multiset算法
分为 质变算法 、非质变算法
质变算法 :运算过程修改容器区间内元素内容
1)例:copy、replace、sort非质变算法 :运算不会修改元素 ,只做查找、统计、遍历
1)例:find、count、for_each(只读版本)迭代器
迭代器是算法访问容器的统一接口,不同容器迭代器能力不同
双向迭代器 :支持
++、--,可以向前、向后遍历;不支持随机跳跃
1)list、map、set 的迭代器随机访问迭代器 :继承双向迭代器能力,额外支持
+n、-n、[],可以直接跳跃访问元素
1)vector、deque 的迭代器三大组件关系总结
- 容器负责存储数据,并对外提供迭代器;
算法通过迭代器,间接操作容器里面的元素,算法本身不依赖具体容器
STL 工作机制
核心原理
1)STL 的核心思想:
容器负责存数据,并且对外提供迭代器(begin ()、end ())
算法不直接访问容器,只通过迭代器区间[begin, end)来遍历、操作元素
2)[begin, end) 左闭右开区间:
begin 指向第一个元素,end 指向最后一个元素的下一个位置,
end 位置不存储有效数据
//模拟数组容器 template <class T> class MyArray { public: //迭代器:把原生指针T* 别名叫做iterator typedef T* iterator; MyArray() { mCapacity = 10; //容量 :总空间大小 mSize = 10; // 有效元素个数 p = new T[mCapacity]; //开辟堆内存 for (int i = 0; i < mCapacity; i++) { p[i] = i + 1; //初始化:1,2,3,4....10 } } //begin:返回起始迭代器,指向第一个元素 T* begin() { return p; } //end,返回结束迭代器,指向末尾下一个位置(无有效数据) T* end() { return p + mSize; } public: T* p;// 堆数组首地址 int mCapacity; //容量 int mSize; //有效数据数量 }; //算法:打印区间元素,不依赖MyArray这个容器 //只要求传入一对迭代器 [begin,end] template <class T> void printArray(T begin, T end) { for (; begin != end; begin++) { cout << *begin << " "; //解引用迭代器,拿到元素 } cout << endl; } void test1() { MyArray<int> arr; //获取迭代器 MyArray<int>::iterator begin = arr.begin(); MyArray<int>::iterator end = arr.end(); printArray(begin, end); }重点
迭代器本质
1)迭代器是容器对外暴露的访问接口
2)对于 list、map,迭代器不是原生指针,但是用法和指针一样(支持*解引用、++)容器和算法解耦(STL 最核心的设计)
1)容器只负责管理内存、存放数据,提供
begin()和end()拿到迭代器
2)算法不关心底层是什么容器,只接收一对迭代器区间[begin,end)
3)算法和容器完全分离,这就是 STL 的精髓左闭右开区间
[begin, end)
1)begin:有效第一个元素
2)end:尾后迭代器,不是有效元素,是判断循环终止条件
3)循环条件:begin != end
typedef T* iterator;作用
1)给指针起别名iterator,模仿 STL 标准写法
2)使用时MyArray<int>::iterator,和vector<int>::iterator写法一模一样STL中的hello world
核心:vector 容器四种用法
- 存放基础数据类型 int
- 存放自定义类对象
- 存放自定义类指针
- 容器嵌套容器
vector<vector<int>>
vector 存放内置数据类型
void MyPrint(int val) { cout << val << " "; } void test1() { vector<int>v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); v.push_back(50); vector<int>::iterator begin = v.begin(); vector<int>::iterator end = v.end(); //for_each : 遍历算法,接收迭代区间+回调函数 for_each(begin, end, MyPrint); cout << endl; }
for_each 底层伪代码
void _For_each(_InIt _First, _InIt _Last, _Fn1& _Func) { for (; _First != _Last; ++_First) _Func(*_First); }1)for_each 会不断移动迭代器,取出元素,传给回调函数
vector 存放自定义对象
重点:vector<Maker>存放的是对象副本,push_back 的时候会拷贝临时对象存入容器
class Maker { public : string name; int age; Maker(string name, int age) { this->name = name; this->age = age; } }; //重载 << 运算符 ,支持cout 打印Maker对象 ostream& operator<<(ostream& out, Maker& m) { out << "Name: " << m.name << " Age: " << m.age << endl; return out; } void test2() { vector<Maker>v; //会调用Maker构造函数,创建临时对象,存入容器(拷贝) v.push_back(Maker("悟空", 18)); v.push_back(Maker("小林", 19)); v.push_back(Maker("贝吉塔", 25)); v.push_back(Maker("龟仙人", 21)); v.push_back(Maker("短笛", 29)); vector<Maker>::iterator begin = v.begin(); vector<Maker>::iterator end = v.end(); while (begin != end) { cout << (*begin); //*begin 取出Maker对象 begin++; } }
vector 存放对象指针
- vector<Maker*>
class Maker { public : string name; int age; Maker(string name, int age) { this->name = name; this->age = age; } }; //重载 << 运算符 ,支持cout 打印Maker对象 ostream& operator<<(ostream& out, Maker& m) { out << "Name: " << m.name << " Age: " << m.age << endl; return out; } void test3() { vector<Maker*>v; //在堆区创建对象 Maker* m1 = new Maker("悟空", 18); Maker* m2 = new Maker("小林", 19); Maker* m3 = new Maker("贝吉塔", 25); Maker* m4 = new Maker("龟仙人", 21); Maker* m5 = new Maker("短笛", 29); v.push_back(m1); v.push_back(m2); v.push_back(m3); v.push_back(m4); v.push_back(m5); vector<Maker*>::iterator begin = v.begin(); vector<Maker*>::iterator end = v.end(); while (begin != end) { //*begin 得到的的是Maker*指针 用->访问 cout << (*begin)->name << " " << (*begin)->age << endl; begin++; } //堆内存必须手动释放 delete m1; delete m2; delete m3; delete m4; delete m5; }
- 区分
1)vector<Maker>:存对象,容器销毁自动销毁对象,不需要手动 delete
2)vector<Maker*>:存指针,容器只保存地址,不会释放堆上的对象,
必须手动 delete,否则内存泄漏
容器嵌套容器
vector<vector<int>>(二维数组效果)
//容器嵌套相当于二维数组 void test4() { vector < vector<int>>vs; vector<int>v1; vector<int>v2; vector<int>v3; vector<int>v4; vector<int>v5; for (int i = 0; i < 5; i++) { v1.push_back(i + 10); v2.push_back(i + 10); v3.push_back(i + 10); v4.push_back(i + 10); v5.push_back(i + 10); } vs.push_back(v1); vs.push_back(v2); vs.push_back(v3); vs.push_back(v4); vs.push_back(v5); vector<vector<int>>::iterator begin=vs.begin(); vector<vector<int>>::iterator end = vs.end(); while (begin != end) { // *begin 得到内层 vector<int> vector<int>::iterator sbegin = (*begin).begin(); vector<int>::iterator send = (*begin).end(); while (sbegin != send) { cout << *sbegin << " "; sbegin++; } cout << endl; ++begin; } }
- 外层迭代器遍历外层容器,解引用*begin拿到内层容器,再取内层迭代器遍历