STL标准模板库

目录

一,容器

1,所有容器

2,常用容器

3,容器主要用法

4,resize和reserve

二,关系模型

1,谁需要关系

2,运算符最小集

3,弱序关系和严格弱序关系

4,相等关系

5,序关系和相等关系的关系

三,算法

1,sort函数

2,find函数

3,lower_bound、upper_bound、equal_range

4,copy函数

5,全排列

四,迭代器

五,用法注意总结

1,map的查完存储现象


C++标准程序库中,属于STL范畴的,粗略估计在80%以上。STL标准模板库是容器和算法组成的。

一,容器

1,所有容器

(1)数组  array    向量 vector

(2)栈  stack

(3)队列 queue     优先队列 priority_queue     双端队列 deque

(4)键值对集合  map    multimap    unordered_map    unordered_multimap 

(5)集合 set   multiset   unordered_set    unordered_multiset  

(6)链表 list   forward_list

在SGI STL中的4个容器是hash_set、hash_map、hash_multiset、hash_multimap(和unordered_***对应)

2,常用容器

容器可以分为3类,常用容器的分类:

(1)顺序容器

链表 list     向量 vector    双端队列 deque

(2)关联容器

set   multiset    unordered_set   

map   unordered_map   

(3)容器适配器

栈  stack   队列 queue     优先队列 priority_queue

3,容器主要用法

(1)顺序容器

链表 list     向量 vector    双端队列 deque

vector是连续内存,data()可以获取其中数组地址。

list是链表,不提供随机访问,支持merge。

 

(2)关联容器

set   multiset    unordered_set   

map   unordered_map   

PS:contains是C++20的新函数

(3)容器适配器

栈  stack   队列 queue     优先队列 priority_queue

4,resize和reserve

    vector<int>v(3);
    cout<<v.size();
    v.reserve(5);
    cout<<v.size();
    v.resize(5);
    cout<<v.size();

输出:3 3 5

这说明,reserve是预留空间,但是并不在容器中,而是在容器外,而resize是直接往容器中扩充了空间。

之所以要预留空间,是因为vector是动态大小,如果插入次数较多,就会涉及到多次的整体搬运内存,效率变得很低。

二,关系模型

STL中的关系模型,是基于离散数学中的二元关系来定义的。

1,谁需要关系

顺序容器、链表不需要,优先队列、关联容器需要,所有算法(包括find成员函数)都需要。

2,运算符最小集

不同的关系模型有不同的运算符最小集,常用的基础运算符是<和==

3,弱序关系和严格弱序关系

快速排序

4,相等关系

(1)查找算法find需要的是相等关系

(2)最小集是{==},可以推导出!=,显然推不出序关系

5,序关系和相等关系的关系

默认情况下,我们用序关系推导出的==和!=表示等序(等价)关系。

但是,我们也可以把2个关系分开定义。

最小集:{<,==}

<可以推导>,再推导出等序关系

==可以推导出!=

等序的元素可能相等也可能不相等。

三,算法

1,sort函数

只有顺序容器可以排序,关联容器和容器适配器不能排序。

常用顺序容器: 链表 list     向量 vector    双端队列 deque

链表排序是用成员sort函数,其他顺序容器是用STL中sort函数,因为链表不支持随机访问,其他顺序容器支持随机访问。

(1)STL中的sort函数

sort

2个必选参数:begin和end,1个可选参数:比较函数

默认升序(相当于less<>()),也可以用函数指针,包括greater<>()、less<>()、自定义函数指针、自定义仿函数

(2)list的成员sort函数

1个可选参数:比较函数

默认升序(相当于less<>()),也可以用函数指针,包括greater<>()、less<>()、自定义函数指针,不能用自定义仿函数

(3)优先队列priority_queue

优先队列priority_queue

优先队列在定义时需要内置比较函数,和list的成员sort函数一样:

默认升序(相当于less<>()),也可以用函数指针,包括greater<>()、less<>()、自定义函数指针,不能用自定义仿函数

小结:所有排序都是默认是less函数,优先队列是以end 作为top,所以默认升序函数就是默认大顶堆。

sort源码里面有一段是这样的:(完整代码参考快速排序和sort

while (_First < _Pfirst
		&& !_DEBUG_LT_PRED(_Pred, *(_Pfirst - 1), *_Pfirst)
		&& !_Pred(*_Pfirst, *(_Pfirst - 1)))
		--_Pfirst;
	while (_Plast < _Last
		&& !_DEBUG_LT_PRED(_Pred, *_Plast, *_Pfirst)
		&& !_Pred(*_Pfirst, *_Plast))
		++_Plast;

即用 !pred(x,y) && !pred(y,x) 推出x==y,所以pred只能是小于,不能是小于等于。

priority_queue里面应该原理差不多。

用这个版本的sort函数做严格弱序测试:

bool cmp(int a,int b)
{
    return a<=b;
}

int main()
{
    int arr[5]={1,3,2,6,2};
    sort2(arr,arr+5,cmp);
    return 0;
}

结果:

然而,我在一次演示的时候翻车了,运行这个代码的结果是正常的:

然后我看了源码,发现内部的sort函数实现方法果然差异很大。

2,find函数

顺序容器采用STL中的find函数,而关联容器采用成员find函数。

用法差不多,返回搜索结果的迭代器,搜索不到返回end,find使用的== 可以重载,即自定义查找条件。

(1)STL中的find函数

常用顺序容器: 链表 list     向量 vector    双端队列 deque   

    list<int>l;
    l.push_back(1);
    auto it = find(l.begin(),l.end(),8);
    if(it==l.end())cout<<"not";
    else cout<<"yes";

虽然链表不是连续内存,但是迭代器可以++,基于此链表可以和连续内存一样进行搜索。

时间复杂度:O(n)

(2)关联容器的成员find函数

    set<int>s;
    s.insert(1);
    auto it = s.find(1);
    if(it==s.end())cout<<"not";
    else cout<<"yes";

时间复杂度:O(log n)

PS:对于multi开头的关联容器,据说是返回第一个进入容器的那一个。

3,lower_bound、upper_bound、equal_range

lower_bound、upper_bound  和 find 一样,顺序容器采用STL中的函数,而关联容器采用成员函数。

 在一个从小到大的数组或者向量或者堆中,

lower_bound(first,last,k)返回第一个大于等于k的元素位置

upper_bound(first,last,k)返回第一个大于k的元素位置

也就是说,从lower_bound(k)到upper_bound(k)-1这一段都是k

比如,在有序向量中查找一个数:

bool has(vector<int>v, int k)
{
	return upper_bound(v.begin(), v.end(), k) != lower_bound(v.begin(), v.end(), k);
}

equal_range是这2个函数的结合,返回pair<iterator,iterator>,2个迭代器的含义同上。

4,copy函数

    set<int>s;
    s.insert(1);
    s.insert(22);
    s.insert(3);
    s.insert(2);
    vector<int>v(4);
    copy(s.begin(),s.end(),v.begin());
    fcout(v);

输出:1 2 3 22

注意,要确保copy的目的地址容量足够,容量不够的时候reserve是不行的,必须resize才行。

5,全排列

 next_permutation 下一个全排列

prev_permutation 上一个全排列

返回值是bool类型,表示操作成功或者操作失败(没有上一个或下一个全排列)

char sn[40];
next_permutation(sn,sn+32); 
prev_permutation(sn,sn+32);    

四,迭代器

STL迭代器

五,用法注意总结

1,map的查完存储现象

map查询之后,就会存储查询的键值对,导致map的内存越来越大。

    map<int,int>m;
    cout<<m.size();
    cout<<m[1];
    cout<<m.size();

输出:001

这也是为什么,用[]访问map是非const的,即使本意只是读。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值