标准模板库(STL)旨在提供通用算法的高效实现,它通过通用函数(可用于满足特定算法要求的任何容器)和方法(可用于特定容器实例)来表达这些算法。
1 STL和C++11
C++11对C++语言做了大量修改,C++11给STL新增了多个元素。首先,它新增了多个容器;其次,给旧容器新增了多项功能;第三,在算法系列中新增了一些模板函数。
1.1 新增的容器
C++11新增了如下容器:array、forward_list、unordered_st以及无序关联容器unordered_multiset、unordered_map和unordered_multimap。
1.2 对C++98容器所做的修改
C++对容器类的方法做了三项主要修改。
2 大部分容器都有的成员
所有容器都定义了表G.1列出的类型。在这个表中,x为容器类型,如vector<int>
;T为存储在容器中的类型,如int。表G.1
中的示例阐明了含义。
类定义使用typedef定义这些成员。可以使用这些类型来声明适当的变量。例如,下面的代码使用迂回的方式,将由string对象组成的矢量中的第一个”bonus“替换为”bogus“,以演示如何使用成员类型来声明变量。
所有的容器都还可以包含表G.2列出的成员函数或操作。其中,X是容器类型,如vector<int>
,而T是存储在容器中的类型,如int
。另外,a和b是类型为X的值;u是标识符;r是类型为X的非const值;rv是类型为X的非const右值,而移动操作是C++11新增的。
表G.2 为所有容器定义的操作
操作 | 描述 |
---|---|
X u | 创建一个名为u的空对象 |
X() | 创建一个空对象 |
X(a) | 创建对象a的拷贝 |
X u(a) | u是a的拷贝(复制构造函数) |
X u=a | u是a的拷贝(复制构造函数) |
r=a | r等于a的值(复制赋值) |
X u(rv) | u等于rv的原始值(移动构造函数) |
X u = rv | u等于rv的原始值(移动构造函数) |
a=rv | u等于rv的原始值(移动赋值) |
(&a)->~X() | 对a的每个元素执行析构函数 |
begin() | 返回一个指向第一个元素的迭代器 |
end() | 返回一个指向超尾的迭代器 |
cbegin() | 返回一个指向第一个元素的迭代器 |
c end() | 返回一个指向超尾的迭代器 |
size() | 返回容器长度,即元素数量 |
maxsize() | 返回容器的最大可能长度 |
empty() | 如果容器为空,则返回true |
swap() | 交换两个容器的长度 |
== | 如果两个容器的长度相同、包含的元素相同且元素排列的顺序相同,则返回true |
!= | a!=b返回!(a==b) |
使用双向或随机迭代器的容器(vector、list、deque、array、set和map)是可反转的,它们提供了表G.3所示的方法。
2.1 关于vector使用的补充
2.1.1 关于拷贝构造函数
有一个点很奇怪,有时间可以研究一下:
#include<iostream>
#include<vector>
using namespace std;
int main(void){
vector<int> element;
for(int i=0;i<10;i++){
element.push_back(i);
}
vector< vector<int> > lista;
for(int i=0;i<2;i++){
lista.push_back(element);
}
lista[0][0]=100;
cout<<lista[0][0]<<endl;
cout<<lista[1][0]<<endl;
return 0;
}
上面程序的输出是:
100
0
这个element不是指针吗,应该指向的是同一块内存空间?有点懵,为什么不变。
3 序列容器的其他成员
模板类vector、forward_list、list、deque和array都是序列容器,它们都包括前面列出的方法,但forward_list不是可反转的,不支持表G.3所示的方法。序列容器以线性顺序存储一组类型相同的值。如果序列包含的元素数是固定的,通常选择使用array;否则,应首先考虑使用vector,它让array的随机存取功能以及添加和删除元素的功能于一身。然而,如果经常需要在序列中间添加元素,应考虑使用list或forward_list。如果添加和删除操作主要是在序列两端进行的,应考虑使用deque。
表G.5 为序列容器定义的其他操作
操作 | 描述 |
---|---|
X(n,t) | 创建一个序列容器,它包含t的n个拷贝 |
X a(n,t) | 创建一个名为a的序列容器,它包含t的n个拷贝 |
X(i,j) | 使用区间[i,j]内的值创建一个序列容器 |
X a(i,j) | 使用区间[i,j)内的值创建一个名为a的序列容器 |
X(il) | 创建一个序列容器,并将其初始化为il的内容 |
a=il; | 将il的值复制到a中 |
a.emplace(p,args); | 在p前面插入一个类型为T的对象,创建该对象时使用与args封装的参数匹配的构造函数 |
待补充 898
表G.6列出了一些序列类(vector、forward_list、list和deque)都有的方法。
操作 | 描述 | 容器 |
---|---|---|
a.back() | 返回*a.end()(最后一个元素) | vector、list、deque |
a.push_back(t) | 将t插入到a.end()前面 | vector、list、deque |
a.push_back(rv) | 将rv插入到a.end()前面;可能使用移动语义 | vector、list、deque |
a.pop_back() | 删除最后一个元素 | vector、list、deque |
a.emplace_back(args) | 追加一个类型为T的对象,创建该对象时使用与args封装的参数匹配的构造函数 | vector、list、deque |
a.push_front(t) | 将t的拷贝插入到第一个元素前面 | forward_list、list、deque |
a.push_front(rv) | 将rv的拷贝插入到第一个元素前面;可能使用移动语义 | forward_list、list、deque |
a.emplace_front() | 在最前面插入一个类型为T的对象,创建该对象时使用与args封装的参数匹配的构造函数 | forward_list、list、deque |
a.pop_front() | 删除第一个元素 | forward_list、list |
a[n] | 返回*(a.begin()+n) | vector、deque、array |
a.at(n) | 返回*(a.begin()+n);如果n>a.size,则引发out_of_range异常 | vector、deque、array |
模板vector还包含表G.7列出的方法。其中a是vector容器,n是x::size_type型整数。
待补充 900
4 set和map的其他操作
Associative containers, of which sets and maps are models, have a Key
template parameter and a Compare
template parameter, which indicate, respectively, the type of the key
used to order the contents and the function object, termed a comparison object, used to compare key values. For the set
and multiset
containers, the stored keys are the stored values, so the key type is the same as the value type. For the map
and multimap
containers, the stored values of one type (template parameter T
) are associated with a key type (template parameter Key
),and the value type is pair<const Key, T>
.Associative containers have
additional members to describe these features,as listed in Table G.9.
表 G.10 为set、multiset、map和multimap定义的操作
操作 | 描述 |
---|---|
创建一个map的方式如下:
map<int,int> test;
判断map中是否存在一个key:
m.count(key) == 0 ;
4.1 Unordered Associative Containers (C++11)
As mentioned earlier, the unordered associative containers (unordered_set
, unordered_multiset
, unordered_map
,and unordered_multimap
) use keys and hash tables to provide rapid access to data. (A hash function converts a key to an index value. For example, if the key were a string, the hash function could sum the numeric codes for the characters in the string and take that sum modulus 13, thus giving an index in the range 0–12.The unordered container would use 13 buckets to store strings.Any string with, say,an index of 4 would be placed in bucket 4. If you wished to search the container for a key, you would apply the hash function to the key and just search the bucket with the corresponding index. Ideally, you would have enough buckets that each one would contain only a few strings.可以删除)
The C++11 library provides a hash<Key>
template that the unordered associative containers use by default. Specializations are defined for the various integer and floating point types, for pointers,and for some template classes, such as string.
Table G.11 lists types used for these containers.
In addition to the Table G.10 methods, the unordered associative containers require several more methods,as listed in Table G.12. In this table, X
is an unordered associative container class, a
is an object of type X
, b
is a possibly constant object of type X
, a_uniq
is an object of type unordered_set
or unordered_map
, a_eq
is an object of type unordered_multiset
or unordered_multimap
, hf
is a value of type hasher, eq
is a value
of type key_equal
, n
is a value of type size_type
,and z is a value of type float.As before, i and j are input iterators referring to elements of value_type, [i, j) is a valid range, p and q2 are iterators to a, q and q1 are dereferenceable iterators to a, [q1, q2) is a valid range, t is a value of X::value_type (which may be a pair),and k is a value of X::key_type.Also il is an initializer_list<value_type> object.
5 STL函数
STL算法库(由头文件algorithm和numeric支持)提供了大量基于迭代器的非成员模板函数。C++标准将算法分成四组:非修改式序列操作、修改式序列操作、排序和相关运算符以及数值操作(C++11将数值操作从STL移到了numeric库中,但这并不影响它们的用法)。序列操作(sequence operation)表明,函数将接受两个迭代器作为参数,它们定义了要操作的区间或序列。修改式(mutating)意味着函数可以修改容器的内容。
5.1 非修改式序列操作
5 find()
template<class InputIterator, class T>
InputIterator find(
InputIterator first,
InputIterator last,
Const T& value
);
find()
函数返回一个迭代器,该迭代器指向区间[first,last]
中第一个值为value的元素;如果没有找到这样的元素,则返回last。
5.2 修改式序列操作
25 reverse
template<class BidirectionalIterator>
void reverse(BidirectionalIterator first, BidirectionalIterator last);
一个使用的例子:
#include<iostream>
#include<algorithm>
using namespace std;
int main(void){
string x="abcde";
reverse(x.begin(),x.end());
cout<<x<<endl;
return 0;
}
输出:
edcba
5.3 排序和相关操作
5.3.1 排序
首先来看看排序算法。
1 sort()
template<class RandomAccessIterator>
void sort(RandomAccessIterator first,RandomAccessIterator last);
template<class RandomAccessIterator,class Compare>
void sort(
RandomAccessIterator first,
RandomAccessIterator last,
Compare comp
);
一个使用的具体例子:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(void){
vector<int> v;
for(int i=3;i>=0;i--){
v.push_back(i);
}
sort(v.begin(),v.end());
for(int i=0;i<4;i++){
cout<<v[i]<<endl;
}
return 0;
}
//输出
// 0
// 1
// 2
// 3
sort()
函数将[first,last)
区间按升序进行排序,排序时使用值类型的<
运算符进行比较。第一个版本使用<
来确定顺序,而第二个版本使用比较对象comp
。
如果想要倒序排序,那么可以进行如下修改:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(void){
vector<int> v;
for(int i=3;i>=0;i--){
v.push_back(i);
}
sort(v.begin(),v.end(),greater<int>());
for(int i=0;i<4;i++){
cout<<v[i]<<endl;
}
return 0;
}
待补充 915