面向对象与泛型编程
(二)算法
各种常用的算法,如sort、find、copy、for_each等
基本概念
- 算法(Algorithms):有限的步骤,解决逻辑或数学上的问题
- 算法的分类
- 质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等。
- 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等。算法主要是由头文件 组成。
遍历算法
for_each(iterator beg, iterator end, _func);//遍历容器
transform(iterator beg1, iterator end1, iterator beg2, _func); //搬运容器到另一个容器中
查找算法
find(iterator beg, iterator end, value);//查找元素
find_if(iterator beg, iterator end, _Pred); //按条件查找元素
adjacent_find(iterator beg, iterator end); //查找相邻重复元素
bool binary_search(iterator beg, iterator end, value); //二分查找法,在无序序列中不可用
count(iterator beg, iterator end, value);//统计元素个数
count_if(iterator beg, iterator end, _Pred); //按条件统计元素个数
排序算法
sort(iterator beg, iterator end, _Pred); //对容器内元素进行排序
random_shuffle(iterator beg, iterator end); //洗牌 指定范围内的元素随机调整次序
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest); // 容器元素合并,并存储到另一容器中
reverse(iterator beg, iterator end);// 反转指定范围的元素
拷贝和置换算法
copy(iterator beg, iterator end, iterator dest); // 容器内指定范围的元素拷贝到另一容器中
replace(iterator beg, iterator end, oldvalue, newvalue); // 将容器内指定范围的旧元素修改为新元素
rreplace(iterator beg, iterator end, oldvalue, newvalue);// 容器内指定范围满足条件的元素替换为新元素
swap(container c1, container c2);// 互换两个容器的元素
算术生成算法#include
accumulate(iterator beg, iterator end, value); // 计算容器元素累计总和
fill(iterator beg, iterator end, value);// 向容器中添加元素
集合算法
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 求两个容器的交集,两个集合必须是有序序列
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);// 求两个容器的并集,两个集合必须是有序序列
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest); // 求两个容器的差集,两个集合必须是有序序列
(三)迭代器
扮演了容器与算法之间的胶合剂。
基本概念
- 提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
- 每个容器都有自己专属的迭代器。迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针。(算法要通过迭代器才能访问到容器)
语法![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fc3e5054729ede3b4c8e265d89b0b64a.png)
(四)仿函数(函数对象)
行为类似函数,可作为算法的某种策略。(留意Lambda表达式)
基本概念
- 概念:
- 重载函数调用操作符()的类,其对象常称为函数对象;
- 函数对象使用重载的()时,行为类似函数调用,也叫仿函数
- 本质:函数对象(仿函数)是一个类,不是一个函数
- 特点:
- 函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值;
- 函数对象超出普通函数的概念,函数对象可以有自己的状态;函数对象可以作为参数传递
- 谓词:
- 返回bool类型的仿函数称为谓词;
- 如果operator()接受一个参数,那么叫做一元谓词;
- 如果operator()接受两个参数,那么叫做二元谓词
(五)适配器
一种用来修饰容器或者仿函数或迭代器接口的东西。
(六)空间配置器:负责空间的配置与管理。
STL内存分配机制,扩容机制之类的
1、STL容器本身的内存分配机制
-
基本概念
- 是通过STL提供的一个默认的allocator实现的。这个allocator是一个由两级分配器构成的内存管理器。
- 当申请的内存大小大于128byte时,就启动第一级分配器通过malloc直接向系统的堆空间分配
- 如果申请的内存大小小于128byte时,就启动第二级分配器,从一个预先分配好的内存池中取一块内存交付给用户。
这个内存池由16个不同大小(8的倍数,8~128byte)的空闲列表组成,allocator会根据申请内存的大小(将这个大小round up成8的倍数)从对应的空闲块列表取表头块给用户。
-
这种做法的优点:
1)小对象的快速分配和释放。当一次性预先分配好一块固定大小的内存池后,对小于128字节的小块内存分配和释放的操作只是一些基本的指针操作,相比于直接调用malloc/free,开销小。小对象是从内存池分配的,这个内存池是系统调用一次malloc分配一块足够大的区域给程序备用,当内存池耗尽时再向系统申请一块新的区域。
2)避免了内存碎片的生成。程序中的小对象的分配极易造成内存碎片,给操作系统的内存管理带来了很大压力,系统中碎片的增多不但会影响内存分配的速度,而且会极大地降低内存的利用率。以内存池组织小对象的内存,从系统的角度看,只是一大块内存池,看不到小对象内存的分配和释放。
3)尽可能最大化内存的利用率。当内存池尚有的空闲区域不足以分配所需的大小时,分配算法会将其链入到对应的空闲列表中,然后会尝试从空闲列表中寻找是否有合适大小的区域。但是,这种内存分配器局限于STL容器中使用,并不适合一个通用的内存分配。因为它要求在释放一个内存块时,必须提供这个内存块的大小,以便确定回收到哪个free list中
2、STL添加元素时是添加一个指向元素的指针还是把值复制一份
- STL容器仅支持“值”语义而不支持“引用(&)”语义,并非因为模板类型参数不能为引用,而是因为如果容器元素为引用类型,就会出现“引用的引用”、“引用的指针”等C++语言不支持的语法和语义。
- 智能指针是一种模拟原始指针行为的对象,因此理论上也可以作为容器的元素,就象原始指针可以作为容器元素一样。但是智能指针毕竟是一种特殊的对象,它们在原始指针共享实值对象的基础能力上增加了自动销毁实值对象的能力,如果将它作为容器的元素,可能导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和“值”语义,也会存在安全隐患,同时也会存在许多应用上的限制,特别是象STL中的auto_ptr这样的智能指针。
3、容器满了的时候如何扩容内存
- 0.5倍、1.5倍或者2倍的扩