第二章 空间配置器
简述空间配置器:
关于一级空间配置器:
直接使用malloc、free、realloc进行内存管理操作。且在内存不足时,会陷入oom_malloc,即模拟C++的set_new_handler。但没有new_handler,则抛出bad_alloc;
关于二级空间配置器:(避免太多小额区块照成内存碎片)
a. 对于申请的内存会up到8的整数倍的大小size,再去据此查找合适的空闲链表。
b. 如果该空闲链表足够,则直接分配;
c. 否则,向内存池申请20个这样的size,如果内存池足够,则返回;
d. 否则,内存池如果有这样的size,则尽可能多的返回;
e. 否则,将内存池的剩余的空间赋予对应的空闲链表,并malloc申请40个这样的size的内存;
f. 如果申请成功,则进行正常返回(留20个在内存池);
g. 如果申请失败,则调用一级空间配置器(其由oom的机制),分配40个这样的size的内存;
h. 如果一级空间配置器成功,则一切ok;否则,会触发bad_alloc;
第三章 迭代器概念与traits编程技法
1)Iterator模式定义如下:提供一种方法使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达式;
2)所谓partial specialization的意思是提供另一份template定义式,而其本身仍为templatized;
3)使用traits获取类型的某一特性,原理为模板参数匹配规则(类似于函数匹配),可以在编译时,确定调用对象。iterator_traits负责萃取迭代器特性,__type_traits则负责萃取型别(type)特性;
第四章 序列式容器
1)vector
采用线性连续空间;(动态空间)
支持Random Access Iterators;(随机访问,时间复杂度为O(1))
插入会导致之后的迭代器失效,如果引起扩容,则全部失效;删除会使得之后的迭代器失效;
2)list
采用环状循环链表;(有辅助头结点)
插入/接合不会使得迭代器失效;删除只会使得当前迭代器失效;
3)deque
采用分段连续线性空间;
允许在常数时间内对头端/尾端进行插入或删除;(当然中间的位置也可以操作,但复杂度高,设计数据的移动)
提供了Random Access Iterator,但是其内部实现复杂;
实现描述:
注:在动map数组时,由于首尾迭代器会指向map对应位置,因此也需要调整首尾迭代器;
注:连续线性空间也被称为缓冲区;
4)stack(适配器,默认使用deque实现)
5)queue(适配器,默认使用deque实现)
6)heap(默认大顶堆)
实现一颗完全二叉树,且父节点大于子节点,并将其放置于vector数组中;(不提供遍历功能和迭代器)
对于插入节点,将其放置于最后的位置,然后进行percolate up上溯:将新节点与父节点比较,如果其值更大,则交换,直至不满足条件或者已达父节点;
对于删除最大节点(即堆顶节点),将其与最后一个元素的位置交换,然后进行percolate down下溯:将该节点和其较大的子节点对换,并持续下放,直至叶子节点;然后再对该叶子节点进行上溯(不能在中间直接停掉吗??)
对于make_heap产生一个堆:从下往上构建堆。
注:将一颗完全二叉树存放在数组中,第一个元素不存放数据,之后将该颗完全二叉树层次遍历放入数组中,那么存在性质:在i处的节点,其左节点必然位于2*i,其右节点必然位于2*i+1;
7)priority_queue
采用heap实现,默认为大顶堆(less);
不提供遍历和迭代器;
8)slist
单向链表;(有辅助头结点)
对于插入、删除、结合等不会使得迭代器失效;但是其中间删除/插入元素的时间复杂度为O(n),因为其需要遍历以获取当前的前一个节点;因此最好在头部进行删除/插入元素操作;
只提供push_front,而不提供push_back;
第五章 关联式容器
1)RB-tree
2)set/map/multiset/multimap
采用RB-tree红黑树实现;
删除/插入新元素,不会导致迭代器失效;
set/map不允许重复,multiset/multimap允许重复;
3)hash_table
线性探测(存在primary clustering问题)、二次探测(存在secondary clustering问题)、开链法;
维护一个指针数组,每一个指针代表一个链表(具有相同的hash值);
在插入数据时,会插入到同一个hash桶中的相同键值的数据旁边;(为什么这么写?)
当出现hashtable中元素个数达到阈值时(SGI是数组大小小于总元素个数时扩容),进行扩容(扩容大小为下一个质数),并将原来的数据rehash到新的表中(原来同一个桶中的数据,现在可能会hash到不同桶中,因此需要一个一个hash,这可能会导致同一个桶的数据出现翻转现象);
4)hash_set/hash_map/hash_multiset/hash_multimap
采用hash_table实现;
hash_set/hash_map不允许重复,hash_multiset/hash_multimap允许重复;
注:我用的版本中,为map/multimap/unordered_map/ unordered_ multimap…
第六章 算法
注:关于快排的median-of-three(三数中值):取头、尾、中央三个位置元素的中值作为pivot;
自省式排序实现描述:
A. 对于要排序的元素数量大于一定值(16),并且快排递归深度没有达到阈值,则使用三数中值快排;
B. 如果快排递归到一定深度(10),则使用堆排序;
C. 对于要排序的元素数量小于等于一定值(16)时,此时不在进行排序;
D. 最后,可以得到一个基本有序的数组,因此可以使用插入排序进行最终的排序;(此时,以16个元素划分,之内无序,在之间是相对有序的)
4. equal_range:寻找value所处的范围;(前提有序)
实现描述:可以在使用二叉搜索找到value后,应用lower_bound查前半部分的下界,以及应用upper_bound查后半部分的下界;
5. nth_element:寻找第n大的元素,并使得前面区域的元素不小于后面的区域的元素;
实现描述:使用median-of-3 partitioning将整个序列分割为更小的左、右子序列;如果nth迭代器位于左子序列,就再对左子序列进行分割,否则再对右子序列进行分割。依此类推,知道分割后的子序列不大于3,便对这个待分割的子序列进行插入排序;
本质上是部分快排;
6. merge sort:归并排序