C++复健3(未整理)
不会用标准库与其他语言没什么区别
C++11的标准库的体系结构与内核分析
C++标准库
C++标准模板库
先明白头文件引用
新式headers
无.h后缀名
旧式headers
带.h后缀名
而新式的headers内的组件都封装与namespace “std”中
旧式的std就不被封装于namespace “std”
标准库属于新式的headres中
STL的六大部件
- 容器Container
- 分配器Allocators
- 算法Algorithms
- 迭代器Iterators
- 泛化的指针
- 适配器Adapters(转换器)
- 容器的适配器
- 迭代器的适配器
- 仿函数的适配器等等
- 仿函数Functors
可以发现OOP的思想跟STL的设计思想是不大一样的
算法的复杂度
当前的常见的Big-oh
- $O(1)$
- $O(n)$
- $O(log_2n)$
- $O(n^2)$
- $O(n^3)$
- $O(2^n)$
- $O(nlog_2n)$
容器大部分都是前闭后开区间,而且不一定是连续空间
一般分三类
Sequence Container
- 顺序容器
Associative Container
- 关联式容器
unordered Container
- 无序容器
HashTable
Separate Chaining
Array
vector
list
Chainingdeque
queue
stack
multiset
multimap
unordered_multimap
unordered_set
非STL
hash_map
hash_set
源码面前,了无秘密
OOP(object oreinted)与GP(generic )的对比
datas 和 methods 结合
datas 与 methods 分离
Allocators
支持容器的内存分配的模块
在不同编译器下不同的分配器得实现源码都是有略微不同的
默认的分配器实际上就只是malloc和free的封装
如果有特殊需求。比如说当实现很多的量,在分配的时候,当我们的值只是一个很小的东西,分配器分配的内存开销相应的就会很大,我们可以指定使用其他的分配器
Container的设计实际上还是根据需求特性来,比如链表的设计核心,结点,数据。需要围绕着其来进行代码上的设计,观察STL库的源码可以发现,C++11看起来似乎糅合了许多OOP的思想(只是似乎),看起来会有些复杂,比如考虑到了对有状态的分配器的支持等等
iterator的设计原则,必须要有五个类型作为特征,并且根据要达到的功能进行各种的重载函数,虽然大体思想还是GP编程
而算法要怎么判断迭代器的类型,并且使用调用达到算法的效果,需要iterator traits来进行甄别。
一般traits 有两个通道,一个是迭代器通道,一个是普通指针通道
deque
双向开口“连续”容器
是一个vector管理着N个array
利用deque做底层结构可以衍生出queue和stack
RB_Tree
RB_Tree的简单理解
红黑结点与root
利用RB_Tree底层结构衍生实现map和set
两者区别在于set 的RBTree 的key = value
而map key = key value = value `
而multiset or multimap 就在RBtree的insert_unique与iinsert_equal区别调用
hashtable
简单理解:多个(有上限)不同规格的桶的连续结合(vector)
桶实际的底层结构是有上限的链表上限一般取决于桶的总个数
超过上限就要增加桶
桶的个数呢一般选择的是质数(1是最小公因数)
增加桶一般是乘2后取左右的质数,所有的桶内的元素都要重新进行分配
所以hashtable也被称作 Separate Chaining
需要知道的是 放入的元素不同,需要指定不同的规则,在设计hashtable的时候需要指定符合规则的行为(谓词)
HashFcn
- 元素映射hash code
- 元素放置规则,注意设计的越杂乱容易不发生元素碰撞
EqualKey
- 元素相等判断
ExtractKey
- key and value区分,为map和set区分服务
c++11后一半都选用unordered_set而不是hash_set,这个名字一开始是民间名字,加入了标准库后,改名哩,虽然hash_set也能用
算法
algorithms
从语言层面讲,是个function template
迭代器的分类
- input_iterator_tag
- farward_iterator_tag
- bidirectional_iterator_tag
- random_access_iterator_tag
- bidirectional_iterator_tag
- farward_iterator_tag
- output_iterator_tag
表继承方式
源码是这样的继承关系
迭代器分类和type traits对算法的影响
pred
返回值都是bool
根据参数的多少被称为N元谓词
标准库中的二分查找(binary_search)基于两个函数
- lower_bound()
- upper_bound()
标准库源代码示例
1 | template<class ForwardIterator, class T> |
functors 仿函数
这个东西基本只为算法服务
标准库中基本又主要的三大类,实际上不止3个
- Arithmetic
- Logical
- Relational
而每一个STL的functors 都需要选择适当的适配分类(adaptable)继承
Adapters适配器
(类似转换头)
container adapters 容器适配器
- stack
- queue
iterator adapters 迭代器适配器
functor adapters 函数适配器
bind2nd是个用来辅助binder2nd函数适配器的辅助函数,帮助记录第一个参数和第二参数的类型,binder2nd再通过知道的类型定义内部成员。俗称,实参类型推导
实际上在C++11中bind2nd 实际使用的是 std::bind 新型适配器
include\
可以绑定函数,仿函数(函数对象),成员函数,成员变量
设计模式adapter