标准模板库(standard template library,STL)是C++十分强大的库,其提供了一组表示容器、蝶代替、函数对象和算法的模板。STL实际上是使用泛型编程(generic programming)编写的,其建立在一些概念的抽象之上,如容器、迭代器、分配器等。OOP和泛型编程的理念不同,OOP关注编程的数据表示,泛型编程关注的则是算法,拥有更高的抽象水平。
以下介绍STL中的泛型编程的理念、容器类、迭代器、算法以及函数对象。
目录
泛型编程
为了能够让泛型编程能够适用于许多类型,泛型编程主要通过类模板和函数模板以及各种抽象概念实现。抽象概念包括分配器、迭代器、容器等。这些抽象概念有对应具体的类,如allocator类、iteration类等。
- STL的几个术语——概念、改进与模型
概念(concept)指的是描述的要求,如对迭代器的基本要求。改进(refinement)指的是概念的继承,如正向迭代器对于输入迭代器、输出迭代器是改进。模型(model)指的是具体实现,例如C++中的iterator类是迭代器的模型。
- 分配器Allocator
分配器Allocator是管理内存的对象。
- 迭代器Iterator
迭代器是能够用来遍历容器的对象,其使得算法可以独立于容器类、具体类型。
迭代器Iterator实际上是满足以下基本概念(concept,STL术语,指一系列要求)的“对象”:
①能解除引用以访问引用值,即定义了解除引用运算符*
②能够实现迭代器之间的复制,即定义了赋值运算符=
③能够实现迭代器之间的比较,即定义了==与!=运算符
④能够遍历容器中的每个对象,即定义了++运算符
从上述要求来看,其实指针和类都可以作为迭代器的具体实现,实际上迭代器就是广义指针。
- 容器Container
容器Container则是可以按照一定结构储存数值的对象,比如数组、链表等。在STL中,容器都是同质的,只能放相同类型的值。
- 函数对象
函数对象是类似于函数的对象,也叫函数符(functor),其指的是可以以函数方式与()结合使用的任意对象。函数名、函数指针、重载了()运算符的类都是函数对象。
迭代器
迭代器是一种概念的抽象,也有具体的实现(即iterator类)。不同算法对迭代器的要求不同,根据不同要求(读写数据、遍历方向、随机访问),其分为5类。每种迭代器均能够满足前文提及的概念,但也具有各自不同的概念。
实际上,这5类迭代器具有一定继承关系:正向迭代器继承了输入迭代器、输出迭代器的所有特点;双向迭代器继承了正向迭代器的所有特点;随机迭代器继承了双向迭代器的所有特点。
- 输入迭代器InputIterator
输入迭代器指的是能从容器中读取信息(但不一定可以修改)的迭代器。其允许读取,但不允许修改。输入迭代器是单向迭代器,只能前进,不能倒退,并且不保证第二遍遍历顺序不变,也不能保证先前值可以被解除引用(是说不能保存先前值后再解除引用?)。
使用输入迭代器的算法必须是单通行(single pass)的,不依赖于前一次遍历时的迭代器值,也不依赖于本次遍历中前面迭代器值(?)。
- 输出迭代器OutputIterator
输出迭代器指能从程序中读取并储存信息到容器的迭代器。其允许解除引用以修改容器值,但不允许读取。
- 正向迭代器Forward Iterator
正向迭代器只使用++遍历,但其每次的遍历顺序相同,并且可以对先前值解除引用(若保存先前值的话),同时可读可写数据(声明const常量即成为只读迭代器)。
使用正向迭代器的算法可以是多通行的。
- 双向迭代器
双向迭代器具有正向迭代器所有特点,但允许前进和倒退,因为它定义了++和--两类运算符。
- 随机访问迭代器
随机访问迭代器具有双向迭代器的所有特点,但允许随机访问(即访问容器中任意元素)。
- C++中一些预定义的迭代器
C++提供了具体的迭代器模型,如ostream_iterator、istream_iterator、reverse_iterator、back_insert_iterator、front_insert_iterator等。它们都包含在头文件iterator中。
· ostream_iterator
ostream_iterator是输出迭代器的模型。其声明的代码如下:/*声明: ostream_iterator<被发送给输出流的类型,输出流的类型> 迭代器对象名(输出流);//构造函数1 ostream_iterator<被发送给输出流的类型,输出流的类型> 迭代器对象名(输出流,数据项的分隔符);//构造函数2 */ //示例 ostream_iterator<int,char> objOI(cout);
· istream_iterator
istream_iterator是输入迭代器的模型。其构造函数和ostream_iterator相近:/*声明: istream_iterator<输入流读取的类型,输入流的类型> 迭代器对象名(输入流);//构造函数1 istream_iterator<输入流读取的类型,输入流的类型> 迭代器对象名(输入流,数据项的分隔符);//构造函数2 */ //示例 istream_iterator<int,char> objII(cin);
· reverse_iterator反向迭代器
reverse_iterator是为了简化函数使用而创建的,其指向序列的末端,对其递增实际上使其递减,其指向原对象之前的对象。常用于反序问题。
· back_insert_iterator、front_insert_iterator、insert_iterator
这三种迭代器均是为了插入算法服务的,都是输出迭代器的模型,但适用于不同的容器类,因此在声明对象时,都需要声明相应的容器类型。
#back_insert_iterator将元素插入到末尾,只能用于允许在尾部插入的容器(如队列queue)
#front_insert_iterator将元素插入到前端,只能用于允许在头部插入的容器(如栈stack、双向队列dequeue)
#insert_iterator则将元素插入到指定位置前,该指定位置通过insert_iterator的构造函数传入
三种迭代器的构造函数如下:/*构造函数 back_insert_iterator<容器类型> 迭代器名(类型对应的容器对象); front_insert_iterator<容器类型> 迭代器名(类型对应的容器对象); insert_iterator<容器类型> 迭代器名(类型对应的容器对象,插入位置); //插入位置实际上也是个迭代器 */ //示例 #include<iterator> #include<iostream> #include<vector> using namespace std; vector<int> v(4); back_insert_iterator<vector<int>> objBII(v); insert_iterator<vector<int>> objII(v,v.begin());
函数对象
- 定义与种类
函数对象也称为函数符(functor),指的是能够与运算符()结合发挥与函数类似作用的任意对象。函数对象包括函数名、函数指针以及重载了()运算符的类对象。
- 函数符的改进——生成器、一元函数、二元函数、一元谓词、二元谓词
函数符按照调用参数、返回类型的不同,分为几种类型:
①生成器(generator):不用参数即可调用的函数符。例如默认构造函数就是一种生成器。
②一元函数(unary function):需要使用一个参数即可调用的函数符。
③二元函数(binary function):需要使用两个参数即可调用的函数符。
④谓词(predicate):返回bool的一元函数称为谓词。
⑤二元谓词(binary predicate):返回bool的二元函数称为二元谓词。 - 一些预定义的函数符
C++在头文件functional中定义了多个模板类函数对象,常用的主要有less<>、greater<>、plus<>等,以下作部分介绍:
· 预定义的函数符
预定义的函数符和许多运算符相对应:运算符 函数符 + plus - minus * multiplies / divides % modulus -(取负) negate == equal_to != not_equal_to > greater < less >= greater_equal <= less_equal && logical_and || logical_or ! logical_not
· 预定义函数符的使用
这些函数符均是用模板写的,因此调用于生成函数符对象时,需要在尖括号内声明相应的类型:
/* //调用于生成函数符对象: 函数符名<类型> 对象名; //调用函数 对象名(左值,右值) //传入容器的构造函数作为比较对象时 //只需传入函数符即可,不需要加上() */ //示例 void main() { plus<int> add; int ans=add(1,2); cout<<ans<<endl; } -----输出----- 3
- 函数符的使用
· 通过类定义一个函数符
如前文所说,重载了()运算符的类也可以作为函数符使用,作为比较对象传入容器构造函数时,只需传入类名即可。
示例代码如下:
上文的代码段中的Greater是针对int类型的,其实也可以像预定义的函数符一样,将其定义为一个类模板,这样其普适性会更强。class Greater//类函数符 { public: Greater(const int & val_a,const int & val_b):a(val_a),b(val_b){}; ~Greater(); bool operator()(){return a>b;}//重载()运算符 private: int a; int b; }; void main() { set<int,Greater> objSet;//传入Greater作为比较对象 }
容器类
容器是按照一定组织结构储存数值的对象,其实就是一系列数据结构的实现(或者用STL的术语来说,模型)。STL中有许多强大的容器类,主要有几大类:
- 序列(如单向链表forward_list、双向链表list、队列queue、矢量vector、双向队列dequeue、优先队列/堆priority_queue)
- 关联容器(如地图/键值对map、集合set、多重映射multimap)
- 无序关联容器(如哈希表unordered_map、unordered_set、unordered_multimap等)。
容器类的基本特征(或者说基本成员)主要有:(X表示序列类型,t为类型T的值,a、b为容器对象,n表示整数,p、q、i、t为迭代器)
表达式 | 返回类型 | 说明 | 时间复杂度 |
X::iterator | - | 满足正向迭代器的任何迭代器 | 编译时间 |
X::value_type | T | T的类型 | 编译时间 |
X u | 创建一个空容器对象u | 固定时间 | |
X() | 创建一个匿名空容器对象 | 固定时间 | |
X u(a) | 迭代器 | 调用复制构造函数,使用容器对象a创建容器对象u | 线性时间 |
X u=a | void | 同X u(a) | 线性时间 |
a.begin() | (常量)迭代器 | 返回指向容器第一个元素的迭代器 | 固定时间 |
a.end() | 迭代器 | 返回指向容器超尾(即最后一个元素以后)的迭代器 | 固定时间 |
a.size() | 整数 | 返回容器元素数 | 固定时间 |
a.swap(b) | void | 交换a和b的内容 | 固定时间 |
a==b | bool | 如果a、b长度相同,且a、b中的每个元素都相同,则返回真 | 线性时间 |
a!=b | bool | 返回!(a==b) | 线性时间 |
编译时间指操作将在编译时执行,执行时间为0;固定时间、线性时间均表示操作在运行时执行,固定时间但独立于对象的元素数,线性时间则与元素数成正比。
以下主要从容器类的特点、声明、方法。介绍各容器类,可以联系数据结构的内容以加深理解。使用各容器前,记得包含它们各自的头文件,头文件名一般与它们的名称相同。
序列
序列是对容器概念的改进,在容器的概念之上,要求:
①迭代器至少应为正向迭代器
②元素应按严格的线性顺序排列
下表总结了每种序列的基本成员的相同部分:(X表示序列类型,t为类型T的值,a为序列对象,n表示整数,p、q、i、t为迭代器)
成员表达式 | 返回类型 | 说明 |
X a(n,t) | - | 声明一个由n个t组成的序列对象a |
X(n,t) | 声明一个由n个t组成的匿名序列 | |
X a(i,t) | 声明一个由区间[i,j)之间的内容组成的序列对象a | |
X(i,t) | 声明一个由区间[i,j)之间的内容组成的匿名序列 | |
a.insert(p,t) | 迭代器 | 将t插入到p前面 |
a.insert(p,n,t) | void | 将n个t插入到p前面 |
a.insert(p,i,j) | void | 将区间[i,j)的内容插入到p前面 |
a.erase(p) | 迭代器 | 删除p |
a.erase(p,q) | 迭代器 | 删除区间[p,q)的内容 |
a.clear() | void | 清空所有内容 |
以下作各序列的简介。各类的方法可以查看相关STL使用目录(例如C++ primer plus第六版的附录G)。
- 单向链表forward_list
单向链表中,每个节点只能链接到下一个节点,即只能前进遍历下一个节点。forward_list使用的是正向迭代器,是不可反转的容器。
其基本操作与list类似,功能较少但更紧凑。
- 双向链表list
双向链表中,除了第一个和最后一个元素外,每个元素都与前后两个节点相链接,即保存有前后两个节点的访问信息。list使用的是双向迭代器,允许双向遍历。list是可反转容器,但不允许随机访问与数组表示法。
list在删除、插入的操作开销是固定时间,遍历则是线性时间。
list提供的成员函数如下:(T为元素类型;Alloc为分配器,一般有默认值;N为元素数)函数 说明 时间复杂度 void merge(list<T,Alloc>&x) 将对象与相同类型的链表x合并 线性时间 void remove(const T & val) 删除val的所有实例 线性时间 void sort() 使用<运算符排序 NlogN void splice(iterator pos, list<T,Alloc> x) 将相同类型链表x插入到p位置前,并且x将被置空 固定时间 void unique() 将连续相同元素压缩为单个元素 线性时间 - 矢量vector
矢量vector是动态数组。它提供了元素的随机访问,需要使用随机访问迭代器。
在尾部删除或插入的时间是固定时间,在头部、序列中间删除或者插入是线性时间。
vector是可反转容器,含有rend()、rbegin()两个方法:函数 返回类型 说明 void rend() reverse_iterator 返回指向反转序列的末尾元素(即正序第一个元素)的迭代器 void rbegin() reverse_iterator 返回指向反转序列第一个元素(即正序最后一个元素)的迭代器 - 队列queue
队列queue只允许在头部删除,尾部插入,不允许随机访问/遍历。
STL中的queue实际上是一个适配器,其让底层类(即实现的基础,STL中默认为deque,实际上也可以用链表、数组实现queue)转换成了队列。
其基本操作如下:函数 说明 bool empty() const 查看队列是否为空 int size() const 查看队列元素个数 T & front() 返回头部元素的引用 T & back() 返回尾部元素的引用 void push(T &x) 将元素x压入队尾 void pop() 删除头部元素 - 双向队列dequeue(doubled-ended queue)
双向队列dequeue允许在头部和尾部插入或者删除。其也提供了随机访问的功能,因此需要使用随机访问迭代器。
其在头部、尾部插入或者删除的时间为固定时间,在序列中间插入或者删除的时间为线性时间。
- 优先队列/堆priority_queue
优先队列/堆priority_queue将最大的元素放在队首,在STL中堆的底层类是vector。
堆支持的操作与queue一样:front()、back()、push()、pop()。堆获取队首元素所需时间是固定时间。声明堆对象时,可以修改用于确定哪个元素放到队首的比较方式:
greater<>是预定义的函数对象。/* priority_queue<元素类型> 堆对象名;//构造函数1 priority_queue<元素类型> 堆对象名(greater<元素类型>)//构造函数2 */
- 栈stack
栈只允许从栈顶插入、删除、访问元素,不允许随机访问、遍历。
stack允许的操作如下:函数 说明 bool empty() const 查看队列是否为空,若为空返回true,非空则返回false int size() const 查看栈元素个数 T & top() 返回栈顶元素的引用 void push(const T &x) 将元素x压入栈顶 void pop() 删除栈顶元素 - 静态数组array
array实际上并不是STL容器,因为其长度是固定的,但是可以将许多STL算法用于array对象,例如copy()、for_each()。
其允许随机访问、遍历。
关联容器
关联容器是对容器概念的改进,其将值与键关联在一起,并使用键查找值。关联容器都提供了对元素的快速访问(其所需时间为固定时间)。关联容器一般通过树实现。
- 集合set、multiset
set、multiset都位于头文件set中。
set中的键是唯一的,不能存储多个相同值,储存的键就是储存的值,故键值类型是一样的。set可以反转,也可以排序。
multiset中可以储存多个重复值,键值仍然相同,并且是按照一定顺序排列的。其是用红黑树实现的。
· set和multiset共有的成员函数 说明 X::key_type 键Key,键类型 X::key_compare 键的比较对象Compare,默认为less<key_type> X::value_compare 值的比较对象Compare,二元谓词类型
· set的成员函数
set的成员函数主要与数学意义上的集合操作相同,具体如下:(i、j为set对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为set<T>::iterator)函数 说明 set<T> A() 创建键值类型为T的set对象A set<T> A(B.begin(), B.end(), c) 创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T> set_union(i, j, p, q, objOI) 并集,将对象A区间[i,j)、对象B区间[p,q)的内容合并并输出到objOI中。objOI需要是输出迭代器,不能是某个容器对象的begin(),因为begin()返回的是常量迭代器,此时可以用insert_iterator。 set_difference(i, j, p, q, objOI) 差集,找出对象A区间[i,j)、对象B区间[p,q)相差的内容,并输出到objOI中。 set_intersection(i, j, p, q, objOI) 交集,找出对象A区间[i,j)、对象B区间[p,q)的相交内容,并输出到objOI中。 A.find(k) 返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end() A.lower_bound(k) 返回一个迭代器,该迭代器指向第一个键不小于 k 的元素 A.upper_bound(k) 返回一个迭代器,该迭代器指向第一个键不大于 k 的元素 A.insert(t) 插入一个值为t的键 A.insert(p, q) 插入B集合中区间[p,q)的值
· multiset成员方法
multiset成员方法如下:(i、j为multiset对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为multiset<T>::iterator)
函数 说明 multiset<T, c=less<T>, Alloc=allocator<T>> A() 创建键值类型为T的set对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T> multiset<T> A(B.begin(), B.end(), c) 创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T> A.find(k) 返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end() A.lower_bound(k) 返回一个迭代器,该迭代器指向第一个键不小于 k 的元素 A.upper_bound(k) 返回一个迭代器,该迭代器指向第一个键不大于 k 的元素 A.insert(t) 插入一个值为t的键 A.insert(p, q) 插入B集合中区间[p,q)的值
· set、multiset的使用#include<iostream> #include<set> using namespace std; int main() { int arrInt[]={12,2,3,5,6}; int array[] = { 0, 2, 1, 4, 3, 6, 5, 7, 8, 9, 0, 7, 6}; set<int> objSET(&arrInt[0],&arrInt[4]); cout<<*objSET.find(2)<<endl;//对返回的迭代器解引用即可获得值 multiset<int> ms(array, array + sizeof(array) / sizeof(array[0])); cout <<*ms.find(6)<<endl; cin.get(); return 0; } -----输出----- 2 6
- 映射map、多重映射multimap
map、multimap都位于头文件map中。它们都是按照键排序的,也可以反转。
map中的键是唯一的,不能存储多个相同值,键、值互相关联,且类型可以不同。multimap中可以储存多个重复键,键、值互相关联,且类型可以不同。
· map和multimap共有的成员函数 说明 X::key_type 表示键Key,类型 X::key_compare 表示键的比较对象Compare,默认为less<key_type> X::value_compare 二元谓词类型,与 set 和 multiset 的 key_compare 相同,为 map 或 multimap 容器中的 pair<const Key, T> 值提供了排序功能 X::mapped_compare 表示值类型,即T
· map的成员函数
set的成员函数主要与数学意义上的集合操作相同,具体如下:(i、j为set对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为map<T>::iterator)函数 说明 map<KT,VT, c=less<KT>,Alloc=allocator<pair<KT, VT>>> A() 创建键类型为KT、值类型为VT的set对象A,比较对象c默认值为less<KT>,分配器Alloc默认为allocator<pair<KT, VT>> map<KT,VT> A(p, q, c) 创建键值类型为T的set对象A,其内容为对象B的区间[p, q)的内容,并使用函数对象c作为比较对象,c默认为less<T> A.find(k) 返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end()。
map<KT,VT>::iterator迭代器实际上指向pair<KT,VT>对象,通过first成员访问键,second成员访问值。A[k] 返回一个指向与键 k 关联的值的引用(map特有的数组表示法) A.lower_bound(k) 返回一个map<KT,VT>::iterator类型的迭代器,该迭代器指向第一个键不小于 k 的元素 A.upper_bound(k) 返回一个迭代器,该迭代器指向第一个键不大于 k 的元素 A.insert(pair<KT,VT>(v,k)) 插入一个键值对为(v,k)的pair对象 A.insert(p, q) 插入B集合中区间[p,q)的值
· multimap成员方法
multimap成员方法如下:(i、j为multimap对象A的区间的迭代器, p、q为对象B的区间的迭代器,objOI是输出迭代器,t为类型T对象,c为用于比较的函数对象,迭代器类型为multimap<T>::iterator)函数 说明 multimap<KT,VT,c=less<KT>,
Alloc=allocator<pair<KT, VT>>> A()创建键类型为KT、值类型为VT的multimap对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T> multimap<KT,VT>A(B.begin(), B.end(), c) 创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T> A.find(k) 返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end() A.lower_bound(k) 返回一个迭代器,该迭代器指向第一个键不小于 k 的元素 A.upper_bound(k) 返回一个迭代器,该迭代器指向第一个键不大于 k 的元素 A.insert(pair<KT,VT>(v,k)) 插入一个键值对为(v,k)的pair对象 A.insert(p, q) 插入B集合中区间[p,q)的值
· map、multimap的使用#include<iostream> #include<set> using namespace std; int main() { int arrInt[]={12,2,3,5,6}; int array[] = { 0, 2, 1, 4, 3, 6, 5, 7, 8, 9, 0, 7, 6}; map<int,int> objmap; multimap<int,int>objMTmap; int arrIntSize=sizeof(arrInt)/sizeof(arrInt[0]); for (int i = 0; i <arrIntSize; i++) { objmap.insert(pair<char,int>(arrInt[i],arrInt[arrIntSize-1-i])); } map<int,int>::iterator objMapI=objmap.find(3); //find()返回迭代器类型为 map<int,int>::iterator //不能使用pair<char,int> objPair来获得返回值 objmap[12]; cout<<"The value of key 3 is : "<<(*objMapI).second<<endl; //map::iterator迭代器指向的是一个pair对象,通过first成员访问键,second成员访问值 cin.get(); return 0; } -----输出----- 3
无序关联容器
无序关联容器也是通过键查找值,但其通过哈希表实现,且元素也是无序的,能够快速存取元素。无序关联容器通过哈希函数计算某个对象的索引,索引相同的对象放在一个桶中,进而只在索引对应的桶中搜索。理想情况下,应有足够多的桶,每个桶只包含为数不多的对象。主要有unordered_map、unordered_set、unordered_multimap三种。
- 无序关联容器共有的成员
以下表格中X表示unordered_set、unordered_map、unordered_multimap中任意一种无序关联容器。函数 说明 X::key_type 表示键Key,类型 X::key_equal 二元谓词binary predicate,用于表示两个类型的Key参数是否相同 X::hasher Hash函数,用于计算索引值的二元函数对象 X::local_iterator 实际上是一个类型与 X::iterator 相同的迭代器,但只能用于一个桶(即一个索引) X::const_local_iterator 实际上是一个类型与 X::const_iterator 相同的迭代器,但只能用于一个桶(即一个索引) X::mapped_type unordered_map 、unordered_multimap中关联数据类型 - 无序关联容器共有的成员方法
无序关联容器的成员方法接口与关联容器类似,拥有的方法也相近,但是没有lower_bound()、upper_bound(),因为它是无序的。需要注意的是unordered_map也支持使用[]和索引值访问桶。
(X表示任意一种无序关联容器类型,n为无序关联容器的桶数,hf为哈希函数,A表示类X的对象,i、j为类X对象A的区间的迭代器, p、q为对象B的区间的迭代器,t为类型T对象,eq为相等谓词,迭代器类型为X<T>::iterator)函数 说明 X<KT,VT,c=less<KT>,
Alloc=allocator<pair<KT, VT>>> A()创建键类型为KT、值类型为VT的无序关联容器对象A,比较对象c默认为less<T>函数对象,分配器Alloc默认为allocator<T> X(n, hf, eq) 创建一个至少包含 n 个桶的匿名空容器,该无序关联容器将 hf 用作哈希函数,将eq用作键值相等谓词。hf默认值为 hasher(), eq默认值为key_equal()。 X A(n, hf, eq) 创建一个至少包含 n 个桶的空容器A,该无序关联容器将 hf 用作哈希函数,将eq用作键值相等谓词。hf默认值为 hasher(), eq默认值为key_equal()。 X A(p, q, n, hf, eq) 创建一个至少包含 n 个桶的空容器,将 hf 用作哈希函数,将 eq 用作键值相等谓词,并插入 区间[p, q]中的元素。n省略时桶数不定;hf默认值为 hasher(), eq默认值为key_equal()。 X<KT,VT> A(B.begin(), B.end(), c) 创建键值类型为T的set对象A,其内容为对象B的区间[begin, end)的内容,并使用函数对象c作为比较对象,c默认为less<T> A.find(k) 返回一个迭代器,该迭代器指向键与 k 相同的元素;如果没有找到这样的元素,则返回 a.end() A.insert(pair<KT,VT>(v,k)) 插入一个键值对为(v,k)的pair对象 A.insert(p, q) 插入B集合中区间[p,q)的值 A.hash_function() 返回A使用的哈希函数 A.key_equal() 返回A使用的键值相等谓词 A.bucket(k) 返回键值为 k 的元素所属桶的索引 A.bucket_size(index) 返回索引为index的桶的所包含的元素 A.bucket_count() 返回A包含的桶数 A.begin(index) 返回一个迭代器,它指向索引为index的桶中的第一个元素 A.end(index) 返回一个迭代器,它指向索引为index的桶中的最后一个元素 A.cbegin(index) 返回一个常量迭代器(即const_iterator),它指向索引为index的桶中的第一个元素 A.cend(index) 返回一个迭代器,它指向索引为index的桶中的最后一个元素 A.rehash(n) 将桶数调整为不小于 n,并确保A.bucket_count() > A.size() / A.max_load_factor()
- 无序关联容器共有的成员方法
- 无序关联容器的使用
与关联容器类似,代码略。
算法
STL中除了容器类的成员方法外,其还含有一些不需要使用容器类对象调用的函数,这些函数主要分为四类:
①非修改式序列操作:面向序列容器的不会修改数据的函数;
②修改式序列操作:面向序列容器的修改数据的函数;
③排序和相关操作
④通用数字运算
前三类放在头文件algorithm,第四类算法放在头文件numeric中。
一般而言,选择容器类的成员方法更加好,因为它更适用于特定容器。
(该部分等使用到了再来补!)