所有容器提供的都是值(value)的语意,而非引用(reference)语意。容器执行插入元素的操作时,内部实施拷贝动作。所以STL容器内存储的元素必须能够被拷贝(必须提供拷贝构造函数)。
除了queue和stack外,每个容器都提供可返回迭代器的函数,运用返回的迭代器就可以访问元素。
通常STL不会丢出异常,要求使用者确保传入正确的参数。
容器的共通能力:
每个容器都提供了一个默认构造函数与一个默认拷贝构造函数。如果已有容器vecIntA,
vector<int>vecIntB(vecIntA);//调用拷贝构造函数
各个容器的使用时机:
vector使用场景:比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录,因为记录是事实的描述。
deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾部的快速添加。若用vector实现类似功能,则会移动大量数据,速度慢。
vector与deque的比较:
1.vector.at()比deque.at()的效率高
2.如果有大量释放操作的话,vector花时间更少
3.deque支持头部的快速插入和快速移除
list的使用场景:比如公交车乘客的存储,随时都有乘车上下车,支持频繁的不确定位置元素的移除插入。
set的使用场景:比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
map的使用场景:比如按ID号存储十万个用户,想要快速通过ID查找对应的用户,这时二叉树的查找效率就体现出来了。如果是vector容器,最坏情况下可能遍历完整个容器才能找到该用户。
常用算法(Algorithm)的用法介绍
算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。
<algorithm>是所有STL文件中最大的一个,其中常用到的功能范围涉及到比较,交换,查找,遍历操作,复制,修改,反转,排序,合并等。
<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。
<functional>中则定义了一些模板类,用以声明函数对象。
STL提供了大量实现算法的模板函数,可以大大简化代码,提升效率。
使用前准备
#include <algorithm>
#include <numeric>
#include <functional>
using namespace std;
常用的查找算法:
adjacent_find(),binary_search(),count(),count_if(),equal_range(),find_if()
常见的排序算法:
merge(),sort(),random_shuffle()(shuffle是洗牌的意思),reverse()
常见的拷贝和替换算法:
copy(),replace(),replace_if(),swap()
常见的算术和生成算法:
accumulate()(accumulate是求和的意思),fill()
常见的集合算法;
set_union(),set_intersection(),set_difference()
常见的遍历算法:
for_each(),transform()(transform是变换的意思)
常见的adjacent_find():在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器。否则返回past-the-end
vecInt包含1,2,2,4,5
vector<int>::iterator it=adjacent_find(vecInt.begin(),vecInt.end());
此时*it==2
binary_search:在有序序列中查找value,找到返回true。注意:在无序序列中不可使用
count:利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。
count_if:利用输入的函数,对标志范围内的元素进行比较操作,返回结果为true的个数
例如vecInt有1,3,5,7,9要求出大于等于3的元素个数:
先定义比较函数:
bool GreaterThree(int iNmu)
{
if(iNum>=3)
{
return true;
}
else
{
return false;
}
}
int iCount=count_if(vecInt.begin(),vecInt.end(),GreaterThree);
此时,iCount==4
equal_range:返回一对iterator,第一个表示lower_bound,第二个表示upper_bound.
find:利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较,当匹配时,结束搜索,返回该元素的迭代器。
如查找5
find(vec,begin(),vec.end(),5);
find_if:使用输入的函数代替等于操作符,执行find,返回被找到的元素的迭代器
find_if(vec.begin(),vec.end(),GreaterThree);
常用的排序算法:
merge:合并两个有序序列,存放到另外一个序列。
例如vecIntA包含1,3,5,7,9,vecIntB包含2,4,6,8
vecIntC.resize(9);//扩大容量
merge(vecIntA.begin(),vecIntA.end(),vecIntB.begin(),vecIntB.end(),vecIntC.begin());
此时,vecIntC就存放了按顺序的1,2,3,4,5,6,7,8,9
sort:以默认升序的方式重新排列指定范围内的元素,若要改排序规则,可以输入比较函数。
vec包含2,1,4,3,6,5
sort(vec.begin(),vec.end());
此时,vec包含了1,2,3,4,5,6
如果vector<T>,T是自定义类型,则要提供T类型的比较函数。
random_shuffle:对指定范围内的元素随机调整次序(随机洗牌)
reverse:对指定范围内元素重新反序排列。
拷贝和替换的算法:
copy:复制序列
例如vecA包含1,3,5,7,9
vecB.resize(5);
copy(vecA.begin(),vecA.end(),vecB.begin());
此时,vecB也包含了1,3,5,7,9
replace(beg,end,oldValue,newValue):将指定范围内的所有等于oldValue的元素替换成newValue。
replace_if(beg,end,GreaterThree,newValue);将指定范围内所有符合GreaterThree条件(自定义条件)结果为true的元素用新值替换。
swap:交换两个容器的元素。
算术:
accumulate(beg,end,value):对指定范围内的元素求和,然后结果再加上一个由val指定的初始值。
fill(beg,end,value)将value赋给标志范围内的所有元素。
常用的集合算法:(与或非逻辑)
set_union(A.begin(),A.end(),B.begin(),B.end(),C.begin()):构造一个有序序列,包含两个有序序列的并集。
set_intersection(A.begin(),A.end(),B.begin(),B.end(),C.begin()):构造一个有序序列,包含两个有序序列的交集。
set_difference(A.begin(),A.end(),B.begin(),B.end(),C.begin()):构造一个有序序列,该序列保留第一个有序序列存在而第二个有序序列不存在的元素。
常用的遍历算法:
for_each:用指定函数依次对指定范围内所有的元素进行迭代访问,该函数不得修改序列中的元素。
定义show函数:
void show(const int &iTem)
{
cout<<iTem;
}
for_each(vec.begin(),vec.end(),show());
以上则打印出vec的所有元素。
transform:与for_each类似,遍历所有元素,但可对容器的元素进行修改。