C++标准库与泛型编程学习笔记
感谢侯捷老师
基础知识
六大部件
- 容器(containers):数据存放在里面
- 分配器(Allocators):支持容器的内存管理
- 算法(Algorithms):一个个模板函数
- 迭代器(Iterators):泛化的指针
- 适配器(Adapters):有容器/迭代器/仿函数适配器,可以帮他们进行转换
仿函数(Functors):相似于函数
1
2
3
4
5
6
7
8
9
10
........
int main(){
int ia[6]={27,210,....};
vector<int,allocator<int>>vi(ia,ia+6);//分配器不写会默认帮你搞好;vi是iterator;
cout<<count_if(vi.begin(),vi.end(),notl(bind2nd(less<int>(),40)));//count_if 是算法,not1是function adapter(negator),表示否定,大于等于40;bind2nd是function adapter(binder),绑定第二参数,这里的作用是有没有小于40;less是function object 仿函数;not1(....)这行称作predicate
}
复杂度 略
“前闭后开”区间:标准库用 c.begin()指的是头,c.end()指向尾巴的后面一个,因此是[);所以*(c.end())是不行的;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25Container<T> c;
....
Container<T>::iterator ite=c.begin();
for(;ite!=c.end();++ite){
.....
}
//range-based for statement C++11
for(decl:coll){
statement;
}
//例子:
std::vector<double>vec;
...
for(auto elem:vec){
std::cout<<elem;
}
for(auto& elem:vec){
elem*=3;//使用引用才能变;
}
//auto的使用;
list<string>c;
list<string>::iterator ite;
ite=::find(c.begin(),c.end(),target);
//等价于
auto ite=::find(c.begin(),c.end(),target);
容器测试
分类:
Sequence Containers(序列式):
Array:固定元素大小的数组
Vector:末端可以扩张的数组
Deque(/dek/):前后可以扩张的数组,双向队列
List:双链
Forward-List:单链,内存小于前者
Associative Containers(关联式):
适合查找
Set/Multiset:集合,底部用红黑树做;Multiset可以重复
Map/Multimap:有序的键/值对,后者的key可以重复,底部用红黑树做;
Unordered Containers(不定序的元素):
Unordered set/Multiset:集合,底部基于哈希-拉链法
Unordered Map/Multimap:有序的键/值对,底部基于哈希-拉链法
容器速率直观比较:
(单位是毫秒)
Array:47,187(项目:50万随机数for循环赋值时间和排序+二分查找时间)
Vector:3063,2765(项目:100万随机数for循环push_back和排序+二分查找时间)a.size()=1000000,a.capacity()=1048576,因为vector增加的时候会预留空间,长着长着开一个两倍的空间复制进去;这个例子里面用find找元素比排序+二分快,0毫秒
List:3265,2312,16(项目:100万随机数for循环push_back和排序+二分查找时间和find的时间),list自带sort
forward_list:3204,15,2656(项目:100万随机数,find的时间,sort的时间) ,它也自带sort
slist:非标准库里面,#include<ext\slist>里面有;和forward_list使用差不多;
deque:2704,15,3110(项目:100万随机数push_back,find函数,使用全局sort)deque的连续是一种假象;它是分段连续,分成一个个buffer,由指针指着;如果buffer用完了就再申请一块buffer;
stack: deque其实涵盖了stack和queue;它们两个的底层都是deque;812(项目:30万随机数push)
queue:890(项目:30万随机数push)
因为stack,queue是由deque实现的,所以也被称为容器适配器
multiset:6609,203,0(项目:100万随机数insert放进去和全局find和自己的find)关联式容器找东西非常快
multimap:4812,0(项目:<index,100万随机数> insert放进去和自己的find)
unordered_multiset:4406,109,0(项目:100万随机数insert进去和全局find和自带find) ;bucket_count()可以看出篮子的个数,篮子一定比元素多;load_factor()可以看出负载因子;
unordered_multimap:4313,0(项目:100万随机数insert进去和自带的find)
set:3922,0,0(项目:100万随机数insert进去和全局find和自带find)
map:4890,0(项目:100万放进去和自带的find);multiset不能用
c[i]=string(buf)
只能用insert函数插入,但是map可以;unordered_map,unordered_set:略
一些老版本的容器比如slist,hash_set,hash_map.hash_multiset,hash_multimap要另外include;
分配器测试:
下面都是GNU-C里面的:
分类器使用示例:
1
template<typename_Tp,typename_Alloc=std::allocator<_Tp>>class vector:protected_Vector_base<_Tp,_Alloc>
不同分配器的使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//使用std::allocator意外的allocator需要自行#include<ext\....>
....
list<string,allocator<string>> c1;
list<string,__gnu_cxx::malloc_allocator<string>> c2;
list<string,__gnu_cxx::new_allocator<string>> c3;
list<string,__gnu_cxx::__pool_allocator<string>> c4;
list<string,__gnu_cxx::__mt_allocator<string>> c5;
list<string,__gnu_cxx::bitmap_allocator<string>> c6;
分配器可以分配内存,但是不如malloc/free;new/delete舒服,释放内存很麻烦;比如:
1
2
3
4int*p;
allocator<int>alloc1;
p=alloc1.allocate(1);
alloc1.deallocate(p,1);