重要网页:
CPlusPlus.com
CppReference.com
gcc.gnu.org
https://zhuanlan.zhihu.com/p/147676383
常用函数:
qsort (c.data(), ASIZE, sizeof(long), compareLongs):快排
c.data():容器的起点
ASIZE:多少个元素
sizeof(long):每个元素多大
compareLongs:比较大小的方式
bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs):二分查找
find(c.begin(), c.end(),target)顺序地从容器中查找
c.begin():c容器中指向第一个元素的迭代器
c.end():c容器中指向超尾(最后一个元素后的下一个空间)的迭代器
target:查询的目标
STL六大部件
容器(containers)
分配器(allocators)
算法(algorithms)
迭代器(Iterators)
适配器(adapters)
仿函式(functors)
容器结构及分类
序列型容器:便于存储
array
vector
deque
list
forward-list
关联型容器:便于查找
set/multiset
map/multiset
unordered set/multiset
unordered map/multiset
array
图示:
大小固定,不能扩充
size()容器内元素的数量
front()容器内第一个元素
back()容器内最后一个元素
data()容器起点的地址
vector
图示:
大小不固定,自动扩充,只能从后面填充数据
当空间不够时,程序会从一个其他位置,获得两倍当前空间的大小,然后从原空间把数据转移到新空间中。
push_back(),从后面添加数据
size()
front()
back()
data()
capacity()容器的容量
deque
图示:
前后扩充,可以从前或从后填充数据
物理上分段连续,逻辑上连续,每次扩充一个buffer
size()
front()
back()
max_size()
list
图示:
双向链表结构
push_back()
max_size()
front()
back()
sort(),这里list自带sort函数
forward-list
图示:
单向链表
push_front()
max_size()
sort()
set/multiset
图示:
利用红黑树实现
key就是value
set是不可重复,multiset允许重复
size()
max_size()
multiset::insert(string(buf)); //buf是一个char类型的数组
find()
map/multimap
图示:
利用红黑树实现
key不可变,value可变,根据key找value
size()
max_size()
multimap::c.insert(pair<long, string>(i, buf)) //multimap不可使用[]做insertion(插入),c是multimap容器
map:: c[i] = string(buf) //map可用[]做插入,第i个元素放入buf
find()
unordered_multiset/unordered_set
图示:
利用哈希表实现
insert(string(buf))
size()
max_size()
bucket_count():篮子的个数(类似于桶排序的桶),篮子数应大于元素的数量,当元素的个数大于等于篮子数时,则将篮子的数量加倍,然后将原来的元素打散后插入新元素。
load_factor()载重因子
max_load_factor()最大载重因子
max_bucket_count()最大篮子数
find()
unordered_multimap/unorder_map
图示:
利用哈希表实现
insert(par<long, string>(i, buf))
size()
max_size()
find()
分配器:为容器提供空间
提供空间,allocator调用new,而new最终调用malloc
malloc在分配空间时,不仅仅给所请求的空间,而且为了回收和其他目的会在分配的空间上添加其他的空间作为记录。
OOP(Object-Oriented programming)与GP(Generic Programming)
OOP企图将data和methods联系起来
GP却将data和methods分开
在GP中data是容器,methods是算法。连接它们的是迭代器
操作符重载
template模板
类模板
泛化:适用于绝大多数
template
struct _type_traits{…};
特化:针对特定的类型进行特定的处理
template<>
struct _type_traits{…};
偏特化:对于有多个模板参数的模板,绑定部分的模板参数
template
class vector<bool, Alloc>
说明:此处确定一个模板参数为bool类型
template
struct iterator_traits<T*>
说明:此处仅仅确定要传出一个指针,但是不确定特定类型
函数模板
成员模板
容器的结构和分类
容器list
代码实现:
结构:
list前闭后开,所以必须建立一个不存放数据的结点(图中的灰色结点)
iterator迭代器,必须是类,模拟指针
一定要提供五个东西
iterator_category,移动方式
difference_type,两个元素之间的距离的表达方式
value_type,元素类型
reference
pointer
由于上面的东西只有结构体或者类中才有,所以如果是指针作为算法的参数时,指针无法提供上面五个东西,所以需要用traits(萃取机,特性、特征、特质)
右边横线下的部分就是算法把迭代器(可能是类,可能是结构体)作为参数时,通过作用符(::)提供算法所需要的五个东西。而横线上的两种情况则需要通过特殊处理(偏特化),特殊处理如下面的2和3.
注意第三种方式,返回值不能时const,因为声明一种不能被赋值的变量是没有意义的,所以不能是const。
完整的iterator_traits:
前++没有参数,后++有参数但参数无意义,仅仅为了与前++区别
后++的第二步调用了前++;
c++允许连续前++,不允许连续后++。
list结点由三部分组成:data,prev_pointer,next_pointer
容器vector
程序实现:
图示:
类似于数组,但是支持自动扩充,但是扩充不是原地扩充,而是遇到空间不足时,从另外一个地方获取当前空间的二倍,然后将元素填充到新空间中。
存在三个指针:
start
finish
end_of_storage
常用函数:
begin():起始迭代器
end():超尾迭代器
size():数量
capacity():容量
empty()
operator:提供随机访问
front()
back()
push_back(const T &x)
insert_aux(iterator position, const T &x)
iterator:
vector中早期的iterator是个指针后面改成了结构体,所以利用traits的对指针偏特化的方式对iterator进行加工
容器array
图示及程序实现:
iterator:
早期也是指针,后面改成了类
容器forward_list
类似于list,不过list是双向,forward_list是单向
容器deque
图示:
结构:分段连续,
添加缓冲区:
图中map中存放着指向buffer(实际存放数据的地方)的指针
在需要添加新的缓冲区时,将新申请到的缓冲区的指针存在map中,这样就实现了双向扩充。
iterator:
cur:当前指向的buffer中的元素的位置
first:当前缓冲区的开始位置
last:指向最后一个元素的下一个位置
node:指向map
缓冲区增长:成倍增长,先分配新的空间,然后将原空间中的元素拷贝到新空间的中间位置,而不是起始位置。
常用函数:
insert(iterator position, const value_type &x),该函数先判断插入的位置是否是头或者尾,如果是直接通过push_front()和push_back()插入,若不是,在看插入的位置在中间位置的左边还是右边,若是左边,则将插入位置左边的所有元素左移copy(front2,pos1,front2),右边copy_backward(pos,back2,back1)同理。
operator
front()
back()
size()
empty()
operator*()
operator->()
operator++()
容器rb_tree
两种插入操作:
insert_unique()
insert_equal()
五个模板参数:
key
value(key + value)
keyofvalue: key如何从value中拿出来
compare:如何比大小
Alloc:分配器
容器set, multiset
data和key是一个东西
不支持利用迭代器更改元素值
set的key必须唯一,所以其insert函数调用rb_tree的insert_unique
multiset元素的key可以重复,所以调用的是insert_equal
容器map, multimap
data和value一同构成value
不可以利用迭代器更改key,但是可以改变data
map的key必须唯一,所以其insert函数调用rb_tree的insert_unique
multimap元素的key可以重复,所以调用的是insert_equal
实现只修改data不修改key的方式
在map声明容器参数时,将容器元素的类型设置为pair<const key, T> value_type, 这就使得key不能该,而data可以改。
创建容器:map<int, string> imap;
map中的独特的operator,在传入参数(key)存在时,返回参数对应的data,在参数不存在时,创建key,将默认值赋给data
容器hashtable
hashtable的容量大于等于元素的个数,则扩大容量。变为距离原来容量两倍最近的素数。然后重新将原空间中的元素重新分配到新空间中。
模板参数:
value
key
hashfcn:如何从对象中找到data
extractkey:如何找到key
equalkey:如何判断相等
算法:
各种容器的iterators
input_iterator_tag
forward_iterator_tag 单向逐个移动,继承input
bidirectional_iterator_tag 双向逐个移动继承forward
random_access_iterator_tag 随机访问继承bidirectional
output_iterator_tag
iterator_category对算法的影响:
由于不同的访问方式所具有的处理效率不同,所以选用正确的方式进行访问对算法的速度是十分重要的。如end()-begin(),若是随机访问,则进行一次操作就可以得到答案,但是如果是forward或者bidirectional则将迭代器走到最后才知道,到底是多少。