stl



Generic Programming	I
第1讲  初识STL	- 1 -
§1.1  什么是泛型程序设计	- 1 -
§1.2  什么是STL	- 1 -
§1.3  STL的核心组件	- 2 -
§1.3.1  容器(container)	- 3 -
§1.3.2  算法(algorithm)	- 3 -
§1.3.3  迭代器(Iterrator)	- 4 -
§1.3.4  函数对象(function object)	- 5 -
§1.3.5  容器、迭代器、算法和函数对象之间的关系	- 8 -
§1.4  建立STL程序的方法	- 8 -
第2讲  STL容器	- 11 -
§2.1  序列式容器	- 11 -
§2.1.1  Vectors.............................................................- 11 -
§2.1.2  Deques…………………………………………………………………...- 20 -
§2.1.3  Lists……………………………………………………………………….- 23 -
§2.2  关联式容器	- 30 -
§2.2.1  操作Set 和Multisets的成员函数及算法	- 30 -
§2.2.2  Set 和Multisets应用实例	- 32 -
§2.2.3  操作Maps和Multimaps的成员函数	- 32 -
§2.2.4  Maps和Multimaps应用实例	- 35 -
§2.3  特殊容器——顺序容器配接器	- 38 -
§2.3.1  Stack(栈).......................................................................................... - 38 -
§2.3.2  Queue(队列).................................................................................... - 40 -
§2.3.3  Priority Queues(优先级队列)	- 41 -
§2.4  Strings可以视为一种STL容器	- 43 -
第3讲  STL迭代器	- 46 -
§3.1  迭代器	- 46 -
§3.2  迭代器的分类(Iterator Categorise)	- 48 -
§3.3  迭代器的算术操作	- 48 -
§3.4  迭代器的区间	- 49 -
§3.5  迭代器的辅助函数	- 51 -
§3.5.1  函数advance(p, n)	- 51 -
§3.5.2  函数distance(first, last)	- 52 -
§3.5.3  函数Iter_swap(p1,p2)	- 53 -
§3.6 迭代器适配器(Iterator Adapters)	- 54 -
§3.6.1  Insert Iterators(安插型迭代器)	- 54 -
§3.6.2  Stream Iterators(流迭代器)	- 56 -
§3.6.3  Reverse Iterators(逆向迭代器)	- 58 -
第4讲  STL函数对象	- 60 -
§4.1  什么是函数对象	- 60 -
§4.2  标准库中预定义的函数对象	- 62 -
§4.3  STL中一元函数对象与二元函数对象的基类	- 66 -
§4.4  函数适配器	- 69 -
§4.5  STL预定义函数对象应用示例	- 74 -
第5讲  STL算法	- 76 -
§5.1  非变异算法	- 80 -
§5.2  变异算法	- 89 -
§5.3  排序算法	- 96 -
§5.4  数值算法	- 102 -
附录  STL基本容器常用成员函数一览	- 106 -
§1  各类容器共性成员函数	- 106 -
§2  顺序容器和关联容器共有函数	- 106 -
§3  容器比较	- 106 -
§4  vector容器常用成员函数	- 106 -
§5  deque容器常用成员函数	- 107 -
§6  list容器常用成员函数	- 108 -
§7  队列和堆栈常用成员函数	- 109 -
§8  优先队列常用成员函数	- 110 -
§9  集合常用成员函数	- 110 -
§10  映射常用成员函数	- 111 -


第1讲  初识STL

§1.1  什么是泛型程序设计
所谓泛型程序设计(Generic Programming,GP),就是编写不依赖于具体数据类型的程序。C++中的模板(包括函数模版与类模版)是泛型程序设计的主要工具。

泛型程序设计的主要思想是将算法从特定的数据结构中分离出来,使算法成为通用的、可以适用于各种不同类型的容器 (数据结构)。这样就不必为每种容器都写一套同样的算法,从而提高了软件的复用性。
显然,泛型程序设计更加通用。
§1.2  什么是STL
STL(Standard Template Library,标准模板库)是一个高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。

从逻辑层次来看,在STL中体现了泛型程序设计的思想,引入了诸多新的概念,比如像容器(container)、算法(algorithmn)以及迭代器(iterator)等。与OOP中的多态(polymorphism)一样,泛型也是一种软件复用技术。

从实现层次看,整个STL是以类型参数化(type parameterized)的方式实现的。这种方式完全基于C++标准中的模板(template),也就是说,整个STL几乎都是类模板和函数模板。


图1-1  STL和C++标准函数库的组件 

STL最初是由HP公司被誉为STL之父的Alexander Stepanov(出生于莫斯科)和Meng Lee开发的一个用于支持C++泛型编程的模板库,1998年被纳入C++标准,成为C++ 标准库的一部分,如图1-1所示。STL是C++发展的重要里程碑。由于C++标准库有多种不同的实现,因此,STL也有多种版本,但它们为用户提供的接口都遵守共同的标准。
§1.3  STL的核心组件
STL主要包含容器、算法、迭代器三大核心部分:
■ STL容器包含了绝大多数数据结构,如数组、链表、字符串、队列、堆栈、树等;
■ STL算法包含了诸如增、删、改、查、排序等系统(全局)函数模板。这些算法都是泛型算法,同一个算法可以适用于任意类型的容器;
■ STL 迭代器类似指针一样,通过它的有序移动,把容器中的元素与算法关联起来,它是实现所有STL功能的基础所在。 
    下面首先看一个简单的STL程序。
【例1-1】从标准输入设备键盘依次输入5个整数5、-3、1、0和8,存入一个向量容器中,然后输出它们的相反数。
#include     
#include       //向量头文件
#include      //迭代器头文件
#include    //算法头文件
#include   //函数对象(仿函数)头文件
using namespace std;  //导入命名空间std

void main() {
		const int N = 5;
		vector s(N);  //定义一个含有5个int类型数据元素的向量容器对象s
		vector::iterator pos; //声明一个向量迭代器pos,该向量元素为int型
        for (int i = 0; i < N; ++i)
                      cin >> s[i];   //从键盘依次输入整数5、-3、1、0和8
                                   //显然,向量容器可以随机访问
cout<<"从键盘输入的5个整数是:"<(cout, ",   "), negate());
	    cout << endl;
}
	程序运行的结果如图1-2所示。






图1-2   例1-1的运行结果
例1-1虽然简单,但却涉及到了STL的3种最关键、最核心的组件:容器(Container)、算法(Algorithms)与迭代器(Iterator)。除此之外,STL还有函数对象(Function  object)、容器适配器(container adaptor)以及STL的其它标准组件。在早期的STL版本中,函数对象又称为仿函数(functor)。下面分别对它们做简单介绍,在后面还要分门别类地比较深入地介绍它们。
§1.3.1  容器(container)
STL中的容器是一种存储有限个T(Template)类型数据元素的集合,每种容器都是一种数据结构。数据元素可以是类的对象本身,如果数据类型T代表的是Class的话。当然,这些数据元素也可以是其它数据类型的数据。例1-1中的s就是一种容器对象,叫做向量容器。容器的内部实现是类模板。
STL提供了七种基本容器,它们被划分为两大类,即序列式容器(Sequence Containers)和关联式容器(Associatve  Containers)。除了基本容器外,STL还提供了一些其它类型的容器,如容器适配器(容器适配器可以看作是由其它容器实现的容器)。
序列式容器中的元素顺序与元素值无关,只与元素插入的次序和存放位置有关。STL预先定义了三种序列式容器,即Vectors(向量)、Deque(双向队列)和List(双向链表)。
关联式容器中的元素位置是按元素值的大小自动排序的,缺省情况下为升序排列。其元素顺序与元素值有关,与元素插入的先后次序无关。关联式容器的底层实现是二叉搜索树的形式。STL中预先定义的关联式容器有Sets与Multisets(集合与多重集合)以及Map与Multimap(映射与多重映射) 。

注意,在C++标准中,STL的组件被组织为13个头文件:。使用不同的容器或容器适配器,需要包含不同的头文件。表1-1列出了常用的容器和容器适配器对应的头文件。因此,今后在STL程序中使用哪种(或哪些)容器时,必须首先将对应的那个(或哪些)头文件包含进来。

表1-1  常用的容器和容器适配器对应的头文件
容器类别	数据结构(容器类)	实现头文件
序列式容器	向量(vector)	
	双向队列(deque)	
	双向链表(list)	
关联式容器	集合(set)、多重集合(multiset)	
	映射(map)、多重映射(multimap)	
容器适配器	栈(stack)	
	队列(queue)、优先级队列(priority_queue)	

§1.3.2  算法(algorithm)
STL提供了大约70多个已经实现了的算法的函数模板,比如算法find()用于在容器中查找等于某个特定值的元素。再如算法sort()用于对容器中的元素进行排序等等。
这样一来,只要熟悉了STL之后,许多代码就可以被大大简化,因为只要直接调用一两个算法模板,就可以完成所需要的功能,从而大大提升软件生产率。

今后在软件的编写过程中,凡是要用到STL中的有关算法,必须先将算法所在的头文件包含进来,即:#include。

STL中的算法分别被组织在头文件当中,其中:
是所有STL头文件中最大的一个(尽管它很好理解),它由一大堆函数模板组成。可以认为头文件中的每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等。

体积很小,只包括几个在序列上面进行简单算术(数值)运算的函数模板,如加法和乘法在序列上的一些操作。涉及到使用STL中的算术(数值)运算方法时,要包含此头文件。

中定义了一些类模板,用以声明函数对象(又称为仿函数)。涉及到使用STL预定义好的仿函数时,要包含此头文件。

总之,算法是应用在容器上并以各种方式处理容器内容(数据元素)的行为或功能。在STL中,算法是由函数模板实现的。要特别注意,这些算法不是容器类的成员函数,相反,它们是独立于容器的全局函数(当然,容器本身也可能具有类似功能的公有成员函数可以使用,而且应该优先使用它们)。因此,不必通过容器对象来调用它们,直接调用即可。

令人吃惊的特点之一就是这些算法是如此地通用,不仅可以将其直接用于STL各种容器,而且还可以用于普通的C++数组或任何其他应用程序指定的容器。 

在例1-1中调用的transform()就是一个算法,其函数模板如下:

template
OutputIterator transform(InputIterator first, InputIterator last,
                           OutputIterator result, Unary_Function op)
{
	for(; first != last; ++ first, ++ last)
		* result = op(*first);
	return result;
}

Transform()算法的功能是顺序遍历first和last两个迭代器所指区间内的诸元素,将每个元素的值作为二元函数对象op的参数,将op执行的返回值通过输出流迭代器result顺序输出。遍历完成后,result迭代器的指向是输出的最后一个元素的下一个位置。
算法transform()会将迭代器返回,但本例的程序忽略了这个返回值。
§1.3.3  迭代器(Iterrator)
容器负责存储数据元素,算法负责加工处理数据元素,那么是谁负责将数据元素从容器里提取出来交给算法去处理呢?又是谁负责将算法处理过的数据元素写入容器呢?这项任务由迭代器负责完成。迭代器将容器与算法耦合起来,通过迭代器可以对容器内任意位置上的元素进行定位和存取(access)。
可以把迭代器看作一个类似于指向容器中元素的被泛化了的普通指针。可以像递增一个指针那样递增迭代器,使其依次指向容器中每一个后继元素;反之,也可以像递减一个指针那样递减迭代器,使其依次指向容器中每一个前驱元素。尽管迭代器类似于指针,但迭代器决不是普通的指针。它们的区别是:指针是指向它所要访问的数据元素的地址,而迭代器是指向它所要访问的数据元素的位置(即容器的某个位置的下标)。但它们也有相同之处,即要访问它们所指的数据元素时,都是在其前面缀“*”运算符。

例1-1中的s.begin()、s.end()以及ostream_iterator(cout, ",   ")都是迭代器。其中
●s.begin()——指向向量容器s的第一个元素位置;
●s.end()——指向向量容器s的末尾位置(即最后一个元素所在位置的下一个位置); 
●ostream_iterator(cout, ", ")——是一个输出流迭代器(实例),其中的ostream_iterator是一个输出迭代器的类模板。本例中通过执行它的构造函数来建立一个输出流迭代器对象,构造时使用的2个参数是输出流对象" cout ",和分隔符", "。ostream_iterator类的实例并不指向STL容器的元素,而是一个输出流对象。假设p是该类型的一个变量(即ostream_iterator类的一个实例,也就是一个ostream_iterator迭代器),那么执行 *p=x 的结果就是将x输出到它所关联的输出流对象,并向其中输出一个分隔符。本例中,输出流迭代器关联到的输出流对象是cout,分隔符是一个逗号,二者都是提供给构造函数的实参。

迭代器是STL的一个关键部分,因为它将算法和容器连在一起,后面将深入讨论它。注意,每种类型的容器都可以定义它的迭代器(一个或多个),若程序中需要使用这类迭代器时可以直接定义。然而,当需要使用另外一类独立于STL容器、但在STL已经预定义了的迭代器时,如输入/出流迭代器,通常需要包含头文件。
§1.3.4  函数对象(function object)
STL中有很多算法(即函数,包含在头文件algorithm中)都需要提供一个称为函数对象(Function Object)的参数。用户可以通过函数对象对容器中的元素实施特定的操作。
尽管在实现函数回调时广泛使用函数指针,但C++STL提供了比函数指针更好的实现回调函数的方法,这就是函数对象。通过函数对象不仅可以实现对函数的调用,而且十分灵活。从语法上讲,函数对象与普通函数的行为是类似的。在早期的STL版本中,函数对象又称为仿函数(functor)。
所谓函数对象,就是重载了函数运算符“()”的那个类的对象(class object)。下面举例说明如何定义和使用函数对象。
1、定义函数对象类
首先,声明一个重载了函数运算符“()”的普通类:

class Negate 
{
public: 
int operator() (int n)  { return -n;}   //重载函数运算符“()”
};

记住,在重载“()”操作符的语句中,第一个圆括弧总是空的,因为它代表重载的操作符是“()”;第二个圆括弧是参数列表。注意,通常在重载其它操作符时,参数数量是固定的(由操作符涉及的操作数个数决定),而重载“()”操作符时有所不同,它可以有任意多个参数。
因为在上面的Negate类中内建的操作(作用是取某数的相反值,此例中该数指定为int类型)是一元的(运算符“-”只有一个操作数),所以重载的“()”操作符也只有一个参数。返回类型与参数类型相同——本例中为int。函数功能是返回与参数符号相反的整数。
2、使用函数对象
现在定义一个叫Callback()的函数来测试上面定义的函数对象类。Callback()有两个参数:一个为int,一个是对类Negate对象(即函数对象)的引用。Callback()将函数对象neg作为一个普通的函数名使用:

#include 
using namespace std;

void Callback(int n, Negate & neg)   //第2个参数是对Negate类对象的引用
{
int val = neg(n);   //调用仿函数neg (),即转化为调用重载的操作符“()”函数 
cout << val<
using namespace std;

class Negate {
        public:
           int operator() (int n) { return -n;}   //重载函数运算符“()”
};

void Callback(int n, Negate & neg)   //第2个参数是对Negate类对象的引用
{
int val = neg(n);   //调用仿函数neg (),即调用重载的操作符“()” 
cout << val< 
T operator() (T t)  {return -t;}  //模板函数对象
};
#include 
#include 
using namespace std;

void main(){
	GenericNegate negate;  //生成类的对象
	cout<< negate(5.3333)< c2
 c1 >= c2
 c1 == c2
 c1 != c2

§2.1  序列式容器
序列式容器中元素的顺序与元素值无关,只与元素插入的先后次序和存放位置有关。STL预先定义好了三种序列式容器,即Vectors(向量)、Deque(双向队列)和List(双向链表)。
STL中的每种序列式容器类都内嵌了一个iterator(迭代器)类,可以由它来定义该容器的iterator。
§2.1.1  Vectors
vector容器是数组的一个泛化推广。由于vector容器内的数据元素被存放在一块连续的内存里,所以,对vector容器内的数据元素可以通过下标法进行随机访问;还可以使用容器的成员函数push_back(i)在容器尾端插入新元素i等;还可以使用它的其它相关成员函数在vector的头部或其它任何位置进行插入、删除操作,参见表2-2。
注意:vector并未提供在其头部插入新元素的push_front成员函数,但可以使用功能相同的其它成员函数执行在vector的头部插入新元素,如insert()成员函数。
vector实际上是一个动态数组,具有内存自动管理功能。对于元素的插入和删除,vector可以动态调整它所占用的内存空间大小。在STL程序中使用向量容器之前,必须包含头文件。      
此外,在定义向量类对象时,必须指定它存储的数据元素的数据类型。因为vector类是一个类模板。例如语句:“vector intList; ”声明了一个存储的元素类型为int的向量容器对象intList。类似地,语句:“vector stringList; ”将stringList声明为一个存储的元素类型为string的向量容器对象。

§2.1.1.1  声明向量对象——vector类中的构造函数
向量容器使用动态数组存储、管理数据元素。因为数组是一个随机访问的数据结构,所以可以随机访问向量中的元素。无论在数组中间,还是在开始处,插入一个元素都是费时的(因为要向后移动元素) ,特别是在数组非常大的时候更是如此。然而在数组末端插入元素却很快(因为不需要向后移动元素)。所以向量容器提供了一个在其末端插入元素的成员函数push_back(i)。
STL程序中使用Vector类的构造函数声明向量对象。Vector类重载了多个构造函数,其中包括默认构造函数,当然还有拷贝构造函数和析构函数。因此,可以通过多种方式来声明和初始化一个向量容器对象(简称向量容器)。表2-1描述了怎样声明和初始化指定类型的向量容器。

表2-1    声明和初始向量容器的方法(vector类的构造函数)
语    句 	作          用
vector vecList; 	创建一个没有任何元素的空向量vecList(使用默认构造函数)
                                                        vector vecList(otherVecList)	创建一个向量vecList,并使用向量otherVecList中的元素初始化该向量。向量vecList与向量otherVecList的类型必须相同
vector vecLIst(size); 	创建一个大小为size的向量vecList,并使用默认构造函数初始化该向量
vector vecList(n,elem); 	创建一个大小为n的向量vecList,该向量中所有的n个元素都初始化为elem
vector vecList(begin,end);   	创建一个向量vecList,以区间(begin,end)做为元素的初值。

§2.1.1.2  操作向量——vector类中的公有成员函数
在介绍了如何声明一个具体的向量容器类对象之后,下面开始讨论如何操作向量容器中的数据元素。必须掌握下面几种基本操作:
      ●元素插入
      ●元素删除
●遍历向量容器中的元素
●返回向量容器中元素的个数
●判定向量容器是否空
假设vecList是一个向量类型容器对象。表2-2给出了在vecList中插入元素和删除元素的操作,这些操作都是vector类的公有成员函数。表2-2还说明了如何使用这些操作。其中多数成员函数被重载(即参数不同)。
                     表2-2     向量容器各种基本操作的成员函数
操作类型	  成员函数	     作     用
删除	vecList.clear()    	从容器中删除所有元素
	vecList.erase(position) 	删除由position指定位置上的元素
	vecList.erase(beg, end)   	删除从beg到end-1区间内的所有元素
	vecList.pop_back()   	删除最后一个元素
插入	vecList.insert(position, elem)   	将elem的一个副本插入到由position指定的位置上,并返回新元素的位置
	vecList.insert(position,
 n, elem) 	将elem的n个副本插入到由 position指定的位置上
	vecList.insert(position, 
beg, end) 	将从beg到end-1之间的所有元素的副本插入到vecList中由position指定的位置上
	vecList.push_back(elem) 	将elem的一个副本插入到向量容器的末尾
重置大小	vecList.resize(num) 	将元素个数改为num。如果size()增加,默认的构造函数负责创建这些新元素
	vecList.resize(num, elem)	将元素个数改为num。如果size()增加,默认的构造函数将这些新元素初始化为elem

§2.1.1.3  在向量容器中声明迭代器
1、声明向量容器的迭代器
vector类内嵌了一个iterator类,它是vector类的一个public成员。通过iterator类可以声明向量容器的一个或多个迭代器,例如语句:
vector::iterator intVeciter;   
将intVecIter声明为int类型的向量容器迭代器。

2、向量容器迭代器的运算表达式
++intVecIter     将迭代器intVecIter前移一个位置,使其指向容器中的下一个元素;
--intVecIter      将迭代器intVecIter后移一个位置,使其指向容器中的前一个元素;
*intVecIter       返回当前迭代器位置上的元素值。

	3、容器的成员函数begin()和end()
	不仅仅向量容器,所有容器都包含成员函数begin()和end()。函数begin()返回容器中第一个元素的位置;函数end()返回容器中最后一个元素的下一个位置。这两个函数都没有参数。
假设有下面的语句:
vector intList;  // intList声明为元素为int类型的向量容器(对象)
vector::iterator intVecIter;// intVecIter声明为元素为int类型的向量容器的迭代器
那么,执行完语句:intVecIter = intList.begin(); 结果迭代器intVecIter将指向容器intList中第一个元素所在的位置。第一个元素所在的位置就是第0号位置。
【示例】下面的for循环将intList中所有元素输出到标准输出设备上:
for (intVecIter = intList.begin(); intVecIter != intList.end();++intVecIter);
                cout<<*intVecList<<"     ";
可以通过表2-3中给出的操作 (均是向量容器的公有成员函数) 来直接访问向量容器中的元素 。
        表2-3 访问向量容器中元素的其它操作(向量容器的其它成员函数)
表达式 	作      用
vecList.at(index) 	返回由index指定的位置上的元素
vecList[index] 	返回由index指定的位置上的元素
vecList.front()   	返回第一个元素(不检查容器是否为空)
vecList.back()   	返回最后一个元素(不检查容器是否为空)

表2-3说明:可以按照数组的方式来处理向量中的元素(注意,在C++中,数组下标从0开始,向量容器中第一个元素的位置号也是0)。

向量类中还包含:返回容器中当前元素个数的成员函数size(),返回可以插入到容器中的元素的最大个数的成员函数max_size()等。表2-4描述了其中的一些操作(注意,假设vecCont是向量容器对象)。

表2-4 计算向量容器大小的操作(向量容器的其它成员函数)
表达式 	作      用
vecCont.capacity() 	返回不重新分配空间可以插入到容器vecCont中的元素的最大个数
vecCont.empty() 	若容器vecCont为空,返回true;否则,返回false
vecCont.size() 	返回容器vecCont中当前实有元素的个数
vecCont.max_size()	返回可以插入到容器vecCont中的元素的最大个数
    
【例2-1】下面给出一个样本程序供进一步认识向量容器成员函数的用法
#include 
#include 
using namespace std;

void main(){
vector intList;
int i;
intList.push_back(13); //在尾部插入元素13
intList.push_back(75);
intList.push_back(28);
intList.push_back(35);
cout<<"Line 1: List Elements: ";
for(i=0;i<4;i++)    //遍历向量容器
  		cout<::iterator listIt;  //声明一个迭代器对象
cout<<"Line 3: list Elements: ";
for(listIt=intList.begin();listIt != intList.end();++listIt)  //通过迭代器访问向量容器
  		cout<<*listIt<<"    ";
cout<    //”vector”头文件
#include 
using namespace std;
int main(void){
		vector v;  //创建一个vector容器对象
		v.push_back(11);  //在末端添加数据元素11
		v.push_back(22);   
		v.push_back(33);
		for(int i = 0; i < v.size(); i++)
			cout << "v[" << i << "] = " << v[i] << endl;  //下标法,随即访问
		return 0;
}   
运行结果如图2-2所示。







图2-2  例2-2运行结果

2、成员函数insert ()
【功能】在任意位置插入一个数据元素
除了push_back()函数可以给vector容器尾部添加元素外,insert()函数则可以在任意位置插入元素。由于插入的时候要先将插入位置后面的元素后移,因此,与push_back函数相比,insert函数耗时比push_back函数久。
【例2-3】下面代码就展示了如何使用insert函数:
#include 
#include 
using namespace std; 
int main(void){
		vector v;
		v.push_back(22);   
		v.push_back(33);
		v.push_back(55);
		v.push_back(66);
		v.insert(v.begin() + 3, 44);  // v.begin() + 3=0+3=3,在v的第3个位置插入44
		v.insert(v.begin(),11);    
		v.insert(v.end(),77);      
		for(int i = 0; i < v.size(); i++)    
			cout << "v[" << i << "] = " << v[i] << endl; 
		return 0;
}  
运行结果如图2-3所示。







图2-3  例2-3运行结果
2、成员函数erase()与clear()
【功能】删除元素
学会了如何给vector容器添加元素以后,当然要知道怎么删除元素了。vector容器提供了erase()函数,可以用来删除指定元素或者迭代器区间[first,last)内的元素。
vector容器还提供另一个删除元素的函数是clear()函数,它在内部调用了erase()函数将[begin(),end())区间的元素全部删除,即清空vector容器。
【例2-4】下面代码展示了如何使用erase成员函数和clear成员函数
#include 
#include 
using namespace std;
void main(void)
{
		vector v; 
		v.push_back(11);
		v.push_back(22);
		v.push_back(33);
		v.push_back(44);
		v.push_back(55);
		v.erase(v.begin()+1); 
		v.erase(v.begin()+2,v.begin()+4);
		vector::iterator i;
		int j;
		for(i=v.begin(), j=0; i!=v.end(); i++, j++)    
					cout<<"v[" << j << "] = " << *i<< endl;
		v.clear();    
		cout << "vector clear()!" << endl;
}
运行结果如图2-4所示。






图2-4  例2-4运行结果

//注:之前用的迭代器是正向,vector还提供了反向迭代器(reverse_iterator,相应的有rbegin(),rend()),具体使用方法跟之前的一样,这里就不举例了。

4、成员函数swap() 
【功能】交换两个同类型vector容器的数据元素
【例2-5】下面代码展示了如何使用swap函数:
#include 
#include 
using namespace std;
void print(vector& v){
		for(int i = 0; i < v.size(); i++)
			cout << v[i] << " ";
		cout << endl;
}
void main(void){
		vector v1; 
		v1.push_back(11);
		v1.push_back(22);
		v1.push_back(33);
		cout << "v1 = ";
		print(v1);
   
		vector v2;
		v2.push_back(44);
		v2.push_back(55);
		v2.push_back(66);
		cout << "v2 = ";
		print(v2);
		v1.swap(v2);  //交换v1和v2的元素
		cout << "After swap:" <头文件。下面先看一个List容器的例子。

【例2-9】首先建立一个空List,然后将‘a’至‘z’的所有字符插入其中,利用循环每次输出并删除第一个元素,直至输出所有元素。
    #include 
#include 

using namespace std;

int main()
{
   		 list coll;      // list container for character elements

   		 // append elements from 'a' to 'z'
    		for (char c='a'; c<='z'; ++c) {
        		coll.push_back(c);      ////成员函数push_back ()在尾部追加一个元素
   	 	}
   	 	
   		 while (! coll.empty()) {        //成员函数empty()是判断List容器是否为空
        		cout << coll.front() << ' ';  //成员函数front()会返回第一个元素
       			 coll.pop_front();       //成员函数pop_front()会删除第一个元素,但不返回
//第一个元素
   	 	}
    		cout << endl;
}
	程序运行结果如图2-9所示。

    




图2-9  例2-9运行结果

§2.1.3.1  List的操作
对List的操作主要是调用它的公有成员函数来实现,它的主要公有成员函数如下:

设list的对象list1和list2分别有元素list1(1,2,3)和list2(4,5,6)。并且由语句”list::iterator it;”声明了list的一个迭代器it。
1.  list构造函数(以元素为int型为例)
list L0;       // 产生一个空list
list L1(9);    // 建一个含9个元素的listt
list L2(5,1);  // 建一个含5个元素其值均为1的list
list L3(L2);   // 建一个L2的copy的list
list L4(L0.begin(), L0.end());  //建一个含L0一个区域的元素的list
 
2.  assign()分配值,有两个重载
L1.assign(4,3);  	// L1(3,3,3,3)
L1.assign(++list1.beging(), list2.end());	// L1(2,3)
 
3.operator= 赋值重载运算符
L1 = list1;	// L1(1,2,3)
 
4.   front()返回第一个元素的引用
int nRet = list1.front()		// nRet = 1
 
5.  back()返回最后一元素的引用
int nRet = list1.back()		// nRet = 3
 
6.  begin()返回第一个元素的指针(iterator)
it = list1.begin();    // *it = 1
 
7.   end()返回最后一个元素的下一位置的指针(list为空时end()=begin())
it = list1.end();
--it;				// *it = 3
 
8.  rbegin()返回链表最后一元素的后向指针(reverse_iterator or const)
list::reverse_iterator it = list1.rbegin();	// *it = 3
 
9.   rend()返回链表第一元素的下一位置的后向指针
list::reverse_iterator it = list1.rend();  // *(--riter) = 1
 
10.  push_back()增加一元素到链表尾
list1.push_back(4) 		// list1(1,2,3,4)

11.  push_front()增加一元素到链表头
list1.push_front(4) 		// list1(4,1,2,3)
 
12.  pop_back()删除链表尾的一个元素
list1.pop_back()  			// list1(1,2)
 
13.  pop_front()删除链表头的一元素
list1.pop_front() 			// list1(2,3)
14.clear()删除所有元素
list1.clear();   // list1空了,list1.size() =0
 
15.  erase()删除一个元素或一个区域的元素(两个重载函数)
list1.erase(list1.begin()); 				// list1(2,3)
list1.erase(++list1.begin(),list1.end());   // list1(1)
 
16.  c.remove(val): 删除容器c中所有值为val的元素
list对象L1(4,3,5,1,4)
L1.remove(4);		 // L1(3,5,1);

17.  c.remove_if(op):删除容器c中所有使op为true的元素
// 小于2的值删除
bool myFun(const int& value) { return (value < 2); }
list1.remove_if(myFun); 	// list1(3) 
 
18.  empty()判断是否链表为空
bool bRet = L1.empty();   //若L1为空,bRet = true,否则bRet = false。
 
19.  max_size()返回链表最大可能长度
list::size_type nMax = list1.max_size();  // nMax = 1073741823
 
20.size()返回链表中元素个数
list::size_type nRet = list1.size();   	// nRet = 3
 
21.  resize()重新定义链表长度(两重载函数)
list1.resize(5)  	// list1 (1,2,3,0,0)用默认值填补
list1.resize(5,4) 	// list1 (1,2,3,4,4)用指定值填补
 
22.  reverse()反转链表
list1.reverse(); 		// list1(3,2,1)
 
23.  sort()对链表排序,默认升序(可自定义回调函数)
● c.sort(): 以操作符<(升序)来排序容器c中所有元素 
● c.sort(op): 以运算子op来排序容器中所有元素

设list对象L1(4,3,5,1,4)
    L1.sort();  				// L1(1,3,4,4,5)
L1.sort(greater()); 	// L1(5,4,4,3,1)
 
24.  merge()合并两个有序链表并使之有序
    ● c1.merge(c2): 假定容器c1和c2包含的元素都已经过排序(sorted with operation < ), 该接口把c2容器中的所有元素移动到c1中并且也按照排序规则排序。
● c1.merge(c2, op): 假定容器c1和c2包含的元素都已经过排序(sorted with op), 该接口把c2容器中的所有元素移动到c1中并且也按照排序规则排序。
● c.reverse(): 反序容器中的元素次序
// 升序
list1.merge(list2);   		// list1(1,2,3,4,5,6) list2现为空
// 降序
L1(3,2,1), L2(6,5,4)
L1.merge(L2, greater());   // list1(6,5,4,3,2,1) list2现为空
 
25.  splice()对两个链表进行拼接(三个重载函数) 拼接后第二个链表清空。要求参与拼接的链表相容 
●  c1.splice(pos, c2):  把容器c2中的所有元素移动到容器c1的迭代器位置pos
之前。  
●  c1.splice(pos, c2, c2pos):  把容器c2中的c2pos位置的元素移动到容器c1
的pos位置之前。(c1和c2可以是同一个容器)。 
●  c1.splice(pos, c2, c2beg, c2end):  把容器c2中的[c2beg, c2end)范围内的所
有元素移动到容器c1的pos位置之前(c1和c2可以是同一个容器)。

list1.splice(++list1.begin(),list2); 
// list1(1,4,5,6,2,3) list2为空
     	list1.splice(++list1.begin(),list2,list2.begin());
// list1(1,4,2,3); list2(5,6) 
list1.splice(++list1.begin(),list2,++list2.begin(),list2.end());
//list1(1,5,6,2,3); list2(4)
 
26.  insert()在指定位置插入一个或多个元素(三个重载函数)
list1.insert(++list1.begin(),9);    // list1(1,9,2,3)
list1.insert(list1.begin(),2,9);    // list1(9,9,1,2,3)
list1.insert(list1.begin(),list2.begin(),--list2.end());  //list1(4,5,1,2,3);
 
27.  swap()交换两个链表(两个重载)
list1.swap(list2);	   // list1(4,5,6) list2(1,2,3)
 
28.  c.unique(): 删除容器中值相同位置相邻的额外元素,只保留一个元素
L1(1,1,4,3,5,1)
L1.unique();			// L1(1,4,3,5,1)

29.  c.unique(op): 删除容器中同时满足op条件位置相邻的额外元素,只保留一个元素
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }
L1.unique(same_integral_part);
§2.1.3.2  List综合示例
 为了更好地理解List容器的成员函数,下面再列举两个例子。
【例2-10】List容器操作的综合例子之一
list仍然包涵了erase(),begin(),end(),insert(),push_back(),push_front()这些基本成员函数。下面来演示一下list的其他函数功能,涉及merge():合并两个排序列表;splice():拼接两个列表;sort():列表的排序。

#include 
#include 
#include 
using namespace std;
 
void PrintIt(list n){
    for(list::iterator iter=n.begin(); iter!=n.end(); ++iter)
      cout<<*iter<<" ";//用迭代器进行输出循环 
}
    
int main()
{
    list listn1,listn2;    //给listn1,listn2初始化 
    listn1.push_back(123);
    listn1.push_back(0);
    listn1.push_back(34);
    listn1.push_back(1123);    //now listn1:123,0,34,1123 
    listn2.push_back(100);
    listn2.push_back(12);    //now listn2:12,100
    listn1.sort();   //给listn1排序
    listn2.sort();    //给listn2排序
    //now listn1:0,34,123,1123         listn2:12,100 
    PrintIt(listn1);
    cout<
#include 
#include 
#include 

using namespace std;

void printLists (const list& l1, const list& l2)
{
    		cout << "list1: ";
    		copy (l1.begin(), l1.end(), ostream_iterator(cout," "));
    		cout << endl << "list2: ";
    		copy (l2.begin(), l2.end(), ostream_iterator(cout," "));
    		cout << endl << endl;
}

int main()
{
    		// create two empty lists
   		 list list1, list2;

   		 // fill both lists with elements
    		for (int i=0; i<6; ++i) {
        		list1.push_back(i);
       			list2.push_front(i);
    		}
    		printLists(list1, list2);

    		// insert all elements of list1 before the first element with value 3 of list2
    		// - find() returns an iterator to the first element with value 3
    		list2.splice(find(list2.begin(),list2.end(),  // destination position
                     		   3),
                 		   list1);                          // source list
    		printLists(list1, list2);

    		// move first element to the end
    		list2.splice(list2.end(),        // destination position
                 		  list2,                // source list
                 		  list2.begin());     // source position
         printLists(list1, list2);

    		// sort second list, assign to list1 and remove duplicates
    		list2.sort();
    		list1 = list2;
    		list2.unique();
    		printLists(list1, list2);

    		// merge both sorted lists into the first list
    		list1.merge(list2);
    		printLists(list1, list2);
} 
程序运行结果如图2-10所示。















图2-11  例2-11运行结果

§2.2  关联式容器
  对于关联式容器,一是要注意这类容器具有自动排序能力,即它们内部的元素总是时刻自动有序的;二是要注意使用Set(集合) 和Multisets(多重集合)之前,必须先包含头文件,而使用Map 和Multimap之前,必须先包含头文件;三是要注意它们支持双向迭代器,但不支持随即迭代器,因此不能随即存取其元素。
一个集合(set)是一个容器,其所包含的元素的值是唯一的,而Multisets所包含的元素的值可以不唯一(即可以有重复元素)。注意,集合(set)与多重集合(Multisets)的内部数据组织是一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,因此,set和Mutilset内部的所有数据元素是自动有序的。
    map(映射)是经过排序的二元组集合,map中的每个元素都是由两个值组成,其中key键值必须是唯一,而另一个值是该元素关联的数值。multimap(多重映射)和映射(map)相似,但其中的键值可以有重复值。map与multimap内部数据的组织也是一颗红黑树,所以它们内部所有的数据元素也都是自动有序的。
§2.2.1  操作Set 和Multisets的成员函数及算法 
 (1)构造函数
定义一个元素为整数的集合intSet,可以用:
                   set  intSet;
 (2) 数据元素基本操作方面的成员函数
插入元素i:intSet.insert(i);
删除元素i(如果存在):intSet.erase(i);
判断元素i是否属于集合: if (intSet.find(i) != intSet.end()) ...
返回集合元素的个数:intSet.size();
判断集合是否空:bool empty() const;
将集合清为空集:intSet.clear()。 

    问题:如何判断一个元素是否在Set中?
方法1:用成员函数count()来判定关键字是否出现,若出现返回值是1,否则返回0。比如查找关键字1是否出现:
               int index = intSet. count(1);
    方法2:用成员函数find()来定位数据元素出现位置,它返回一个迭代器,当set中包含该数据元素时,返回数据元素所在位置的迭代器;如果不包含,返回的迭代器等于end函数返回的迭代器。比如查找关键字1是否出现:
		if (intSet.find(1) == intSet.end()) 	
   	             cout<<”Not Find ”<<1< equal_range(const Key& key) const; 	 // 返回//容器中元素值等于key的迭代指针[first, last)
const_iterator find(const Key& key) const; //查找功能返回元素值等于key迭代器指针
void swap(set& s); 	  //交换单集合元素
void swap(multiset& s); 	  //交换多集合元素

(5) 集合的算法
 STL中的算法包含在  头文件中,集合的算法也包含在该头文件中。
集合的并:set_union
集合的交:set_intersection
集合的差:set_difference
§2.2.2  Set 和Multisets应用实例
【例2-12】
#include 
#include 
	using namespace std;

int main(){
    		  typedef std::set IntSet;
   		 IntSet coll;        // set container for int values
   		 coll.insert(3);  //所有关联式容器都提供一个insert()函数,用以安插新元素,且
//自动完成排序
    		coll.insert(1);
   		 coll.insert(5);
   		 coll.insert(4);
   		 coll.insert(1);
    		coll.insert(6);
    		coll.insert(2);

    		IntSet::const_iterator pos;
    		for (pos = coll.begin(); pos != coll.end(); ++pos) {
        		std::cout << *pos << ' ';
    		}
    		std::cout << std::endl;
}
运行结果如图2-12所示。






图2-12  例2-12运行结果

§2.2.3  操作Maps和Multimaps的成员函数  
map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可称为该关键字对应的值,即即一个数据元素为key/ value对的形式)的数据处理能力。map内部数据的组织也是一棵红黑树,所以map内部所有的数据元素都是自动有序的。
那么什么是一对一的数据映射?比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可以轻易描述,很明显学号用int描述,姓名用char *字符串描述,如下面的map描述代码:
             map  mapStudent;
一、STL中的通用工具pair与make_pair的用法
C++ STL预定义了几个通用工具类(或结构体)、函数等,结构体pair与函数make_pair()就是其中的两个。它们定义在通用工具头文件内,使用它们之前必需包含此头文件。
1、pair的应用
Pair的用途是将2个数据构造为一个数据元素(通过其构造函数)。当有这样的需求时就可以使用pair来构造,如STL中的容器map就是将key和value放在一起作为一个元素来保存的,因此,构造map的数据元素时就要用到pair。pair的另一个应用是,当一个函数需要返回2个值的时候,可以选择pair这种数据类型。 pair的实现是一个结构体,主要的两个成员变量是first 和second。 因定义pair是使用struct不是class,所以可以直接使用pair的成员变量(因为struct的成员都是public成员)。

std::pair模型:
template     
    	struct  pair   
    	{   
        	T1   first;       //key值部分
        	T2   second;   //value部分
   
pair(const T1  a, const T2  b) : first(a), second(b) { } //构造函数
   		};   
如:std::pair(3, 1.1);将构造一个视为一个数据元素整体来对待的数对(3,1.1),其中3为int型,1.1为float型。

2、便捷函数make_pair()
    便捷函数make_pair()的作用也是将2个数据构造为一个数据元素(make_pair()的返回值)。make_pair()的函数模版声明如下:

    template 
pair  make_pair (const T1  x, const T2  y)
{
return pair(x, y);  //调用pair类的构造函数
}

例如:std::make_pair(42,‵@′);与std::pair(42,‵@′);都是返回一个由(42, ‵@′)组成的数对(42,‵@′),显然,std::make_pair(42,‵@′)更简便,而pair在有些编译器下不允许这么简便写。
二、操作Maps和Multimaps的成员函数
(1)构造函数
map共提供了6个构造函数,通常用图2-13所示的方法构造一个Map。






图2-13  构造map的常用方法
(2)数据的插入的三种方法
第一种方法:用insert函数插入pair数据
     mapStudent.insert(pair(1, “student_one”));
第二种方法:用insert函数插入value_type数据
     mapStudent.insert(map::value_type(1, “student_one”));
第三种方法:用数组方式插入数据
     mapStudent[1] =  “student_one”;
     mapStudent[2] =  “student_two”;

(3) 数据的删除
   //如果要删除数据元素1,用迭代器删除
	map::iterator iter;
	iter = mapStudent.find(1);
	mapStudent.erase(iter);

(4) 数据的查找
第一种方法:用count函数来判定关键字是否出现,返回1,元素存在;否则返回1。比如查找关键字1是否存在?
        int index = mapStudent. count(1);
第二种方法:用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器:
	map::iterator iter; 
	iter = mapStudent.find(1);
	if (iter != mapStudent.end())
		    cout<<”Find, the value is ”<second<
#include 
using namespace std;
 
int main(){
    map > map1;
    map >::iterator mapIter;
    //char 是键的类型,int是值的类型, less要求升序
    //下面是初始化,与数组类似
    //也可以用map1.insert(map >::value_type(''c'',3)); 
    map1['c']=3;
    map1['d']=4; 
    map1['a']=1;
    map1['b']=2; 
    for(mapIter=map1.begin();mapIter!=map1.end();++mapIter)
        cout<<" "<<(*mapIter).first<<": "<<(*mapIter).second;
    //first对应定义中的char键,second对应定义中的int值  
    //检索对应于d键的值是这样做的:
    map >::const_iterator ptr; 
    ptr=map1.find('d');
    cout<<'\n'<<" "<<(*ptr).first<<" 键对应于值:"<<(*ptr).second<
#include 
#include 
using namespace std;
 int main(){
    multimap >mulmap;
    multimap >::iterator p;
    //初始化多重映射mulmap: 
    typedef multimap >::value_type vt;
    typedef string s;
    mulmap.insert(vt(s("Tom "),s("is a student")));
    mulmap.insert(vt(s("Tom "),s("is a boy")));
    mulmap.insert(vt(s("Tom "),s("is a bad boy of blue!")));
    mulmap.insert(vt(s("Jerry "),s("is a student")));
    mulmap.insert(vt(s("Jerry "),s("is a beatutiful girl")));
    mulmap.insert(vt(s("DJ "),s("is a student")));
    //输出初始化以后的多重映射mulmap: 
    for(p=mulmap.begin();p!=mulmap.end();++p)
        cout<<(*p).first<<(*p).second<
#include 
#include 
using namespace std;

int main(){
    	// type of the collection
    	typedef multimap IntStringMMap;

    	IntStringMMap coll;        // container for int/string values

    	// insert some elements in arbitrary order
    	// - a value with key 1 gets inserted twice
    	coll.insert(make_pair(5,string("tagged")));
    	coll.insert(make_pair(2,string("a")));
    	coll.insert(make_pair(1,string("this")));
    	coll.insert(make_pair(4,string("of")));
    	coll.insert(make_pair(6,string("strings")));
    	coll.insert(make_pair(1,string("is")));
    	coll.insert(make_pair(3,string("multimap")));

    	/* print all element values
     	* - iterate over all elements
     	* - element member second is the value
     	*/
    	IntStringMMap::iterator pos;
    	for (pos = coll.begin(); pos != coll.end(); ++pos) {
        	cout << pos->second << ' ';  //输出pos所指数据元素的second部分
    	}
    		cout << endl;
}
程序运行结果如图2-16所示。







图2-16 例2-15运行结果

【例2-16】
#include 
  #include 
  #include 
  using namespace std;
  
  int main () {
    pair  product1 ("tomatoes",3.25);
    pair  product2;
    pair  product3;
 
    product2.first = "lightbulbs";     // type of first is string
    product2.second = 0.99;        // type of second is double
    product3=make_pair(string("shoes"),20.0); 
 
    cout << "The price of " << product1.first << " is $" << product1.second << "\n";
    cout << "The price of " << product2.first << " is $" << product2.second << "\n";
    cout << "The price of " << product3.first << " is $" << product3.second << "\n";
    return 0;
  }
本程序运行结果如图2-17所示。








图2-17   例2-16运行结果

§2.3  特殊容器——顺序容器配接器
为了满足特殊的需要,C++标准程序库还提供了一些特殊的、依据vector、list等基本顺序式容器预先定义好的容器配接器(Containers Adapters)。容器配接器包括:Stacksa(栈)、Queues(队列)和Priority Queues(优先级队列)。所谓容器配接器,就是使一种已存在的容器类型在实现时采用另一种的抽象类型的工作方式。
§2.3.1  Stack(栈)
Stack容器是一个先进后出(FILO)的数据结构。值得注意的是迭代器不能在堆栈中使用,因为只有栈顶的元素才可以访问。使用stack时必须包含头文件,并使用统一命名空间。
1、构造函数
构造函数用于声明一个堆对象,如:
stack();        //声明一个空栈
stack(copy);   //用一个栈对象copy初始化新栈
    stack s1;
    stack s2;

stack模板类需要2个模板参数,第一个为元素类型,第二个为容器类型。其中元素类型是必要的。而容器类型缺省时,默认为deque。

2、成员函数
所有的这些操作可以被用于堆栈. 相等指堆栈有相同的元素并有着相同的顺序。
①  empty()
语法:   bool empty();
功能:  判断栈是否为空。如空返回 true, 否则返回false。
②  pop()
语法:  void pop();
功能: 退栈。pop() 函数移除栈顶元素。
③  push(x)
语法:  void push( const TYPE &val );
功能: push(x) 函数将x压栈,使其成为栈顶元素。
④  size()
语法:  int size();
功能:size() 函数返当前堆栈中的元素数目。
⑤  读取栈顶元素top()
语法:  TYPE & top();
功能: top() 函数栈顶元素的引用。 

【例2-17】
#include 
#include 

using namespace std;

void main(){
    stack st;

    // push three elements into the stack
    st.push(1);
    st.push(2);
    st.push(3);

    // pop and print two elements from the stack
    cout << st.top() << ' ';
    st.pop();
    cout << st.top() << ' ';
    st.pop();
    // modify top element
    st.top() = 77;
    // push two new elements
    st.push(4);
    st.push(5);

    // pop one element without processing it
    st.pop();

    // pop and print remaining elements
    while (!st.empty()) {
        cout << st.top() << ' ';     st.pop(); }
    cout << endl;
}
本程序运行结果如图2-18所示。







图2-18   例2-17运行结果
       
§2.3.2  Queue(队列)
Queue实现的是一个先进先出(FIFO)队列。使用queue时必须包含头文件,并使用统一命名空间。
1、构造函数
queue()           //声明一个空队列;
queue(mycont)     //声明一个队列,它的初始内容复制自mycont;
2、成员函数
① push():    //将一个新元素加入到队列的末端;
② pop():     //弹出队列中的第一个元素,返回的是一个void;
③ front():    //存取队列中的第一个元素,返回的是一个引用;
④ back():   //存取队列中的最后一个元素,返回的是一个引用;
⑤ empty():  //测试队列是否为空;
⑥ size():    //获得队列中元素的个数;

3、常见的六种比较操作同样适用
【例2-18】
#include 
#include 
#include 
using namespace std;

int main(){
    queue q;

    // insert three elements into the queue
    q.push("These ");
    q.push("are ");
    q.push("more than ");

    // read and print two elements from the queue
    cout << q.front();
    q.pop();
    cout << q.front();
    q.pop();

    // insert two new elements
    q.push("four ");
    q.push("words!");

    // skip one element
    q.pop();

    // read and print two elements
    cout << q.front();
    q.pop();
    cout << q.front() << endl;
    q.pop();
    // print number of elements in the queue
    cout << "number of elements in the queue: " << q.size()
         << endl;
}
本程序运行结果如图2-19所示。







图2-19   例2-18运行结果

§2.3.3  Priority Queues(优先级队列)
priority_queue也是一个队列,不过该模版类可以保证每次通过pop(出队)从它里面取得的元素都是剩下元素中优先级最高的,在每次通过push(入队)添加元素时,整个序列都会在必要时进行重排,它使用堆算法保持序列的有序化。使用priority_queue时必须包含头文件,并使用统一命名空间。
1、构造函数
① priority_queue() :      //声明一个按pred()排序的空优先队列;
② priority_queue(pr) :     //声明一个按函数对象pr排序的空优先队列;
③ priority_queue(pr,mycont)       //声明一个按pr排序的优先队列,它的初始内容
//是从mycont中复制过来并排序的;
④ priority_queue(first,last) :      //声明一个按pred()排序的优先队列,初始内容从//指定序列中复制过来的;
⑤ priority_queue(first,last,pr) :     声明一个按pr排序的优先队列,它的初始内容是//从指定的序列中复制过来并排序的;
⑥ priority_queue(first,last,mycont,pr) :   //声明一个按pr排序的优先队列,它的初内//容复制从mycont中指定的段并排序;

2、priority_queue的主要成员函数如下:
① push():   //向优先队列中压入一个新元素;
② pop():    //从优先队列中弹出它的顶端元素,返回值是void;
③ top():    //存取优先队列中顶端的元素,返回的是一个常量的引用;
④ empty(): //测试优先队列是否为空;获得优先队列中元素的个数;

3、常用的六种比较操作同样适用
【例2-19】
#include 
#include 
using namespace std;

int main()
{
    priority_queue q;
    // insert three elements into the priority queue
    q.push(66.6);
    q.push(22.2);
    q.push(44.4);

    // read and print two elements
    cout << q.top() << ' ';
    q.pop();
    cout << q.top() << endl;
    q.pop();

    // insert three more elements
    q.push(11.1);
    q.push(55.5);
    q.push(33.3);
    // skip one element
    q.pop();
    // pop and print remaining elements
    while (!q.empty()) {
        cout << q.top() << ' ';
        q.pop();
    }
    cout << endl;
}
本程序运行结果如图2-20所示。







图2-20   例2-19运行结果

§2.4  Strings可以视为一种STL容器
STL是个框架,除了提供标准容器外,也允许使用其它数据结构作为容器,如使用字符串或数组等作为容器。
Strings可被视为以单个字符(characters)为元素的一种容器:若干个字符构成序列(即一个字符串),可以在序列上来回移动遍历。因此,标准的string 类也提供成员函数begin()和end(),返回随机存取迭代器,可用来遍历整个string。同时,string还提供了诸如push_back()等成员函数。使用string类型,必须包含头文件。

1、string类型的初始化(构造函数)
string s1;       //定义串s1,s1为空串
string s2(s1);	   //用s1初始化s2
string s3(“abcdefg”); 
string s4(s3, 2);	
string s5(s3.begin(), s3.begin()+2); 
string s6(s3,2,3);	
string s7(5,’x’);   
cin >> s1;	
cout << s2 << endl;   //输出s2

2、string对象基本操作的成员函数 
	string对象提供的基本操作(成员函数)列于表2-6中。

3、string 应用举例
string s1("abc");
	string s2("xyz");
	s1+=s2+"1234";				//s1="abcxyz1234"
表2-6  string对象的基本操作
操作接口示例
s1、s2均为string对象	说     明
s1=s2	将s2的副本赋值给s1
s1.empty()	如果s1为空串,返回true,否则返回false
s1.size()	返回s1中字符的个数
s1[n]	返回s1中位置为n的字符,位置从0开始计
==,!=,<,<=,>,>=,	关系运算符保持原有的含义
s1+=s2或s1=s1+s2	将s2表示的串追加到s1的后面形成新串
s1.insert(pos, s2)	在下标为pos的元素前插入s2表示的串
s1.insert(pos, cp, len)	在下标为pos的元素前插入cp所指串的前n个字符
insert操作还有很多用法,在这里不再一一列举
s1.c_str()	返回s1表示的串的首地址
s1.substr(pos, n);	返回一个string类型的字符串,包含s1中从下标pos开始连续n个字符
s1.append(s2)	将s2表示的串追加到s1的后面形成新串
s1.append(cp)	将字符指针cp指向的串追加到s1的后面形成新串
s1.replace(pos, len, s2)	删除s1中从下标pos开始的len个字符,并用s2替换之
s1.find(s2, pos)	从s1下标为pos的位置开始查找s2,找到后返回s2第一次出现的位置,若没找到,返回值string::npos
                                             s1.rfind(s2, pos)	从s1下标为pos的位置开始查找s2,找到后返回s2最后一次出现的位置,若没找到,返回值string::npos
s1.find_first_of(s2,pos)	从s1下标为pos的位置开始查找s2中的任意字符,找到后返回第一次出现的位置。
s1.find_last_of(s2,pos)	从s1下标为pos的位置开始查找s2中的任意字符,找到后返回最后一次出现的位置。

	bool tag = s1>s2 ? true:false;   //tag=0
	int pos = 2;
	s1.insert(pos, s2);		        //s1 = "abxyzcxyz1234"
	s1.insert(pos, "12345", 4);	    //s1 = "ab1234xyzcxyz1234"
	string s3 = s1.substr(pos, 6);  //s3 = "1234xy"
	s3.append(s2);			   //s3 = "1234xyxyz"
	s1.replace(pos, 4, "k");    //s1 = "abkxyzcxyz1234"
	int p = s1.find(s2, pos);	//p = 3
	p = s1.rfind(s2);		    //p = 7
	p = s1.find_first_of(s2);	//p = 3
	p = s1.find_last_of(s2);	//p = 9
	
//拷贝到字符数组中
	char * cp = new char [s1.size()+1];
	strcpy(cp ,(char *) s1.c_str ());     //cp = "abkxyzcxyz1234"




第3讲  STL迭代器  

§3.1  迭代器
迭代器(Iterators)是一个“可遍历容器内全部或部分元素”的对象。迭代器被用来指向容器中某个特定数据元素的位置(如同下标),其作用有点像指针,但绝不是普通的指针。它是被泛化了的指针。迭代器多半作为参数传递给算法。
(1) 每种容器类型都定义了自己的迭代器类型,如vector容器:
语句vector::iterator iter; 就定义了一个迭代器。 由于iterator类是容器类的一个内嵌类,所以这条语句是定义了一个名为iter的、vector类的iterator类型的变量(即iterator类的一个对象,即迭代器iter)。同时,这条语句还指定vector的数据元素为int类型数据。
 (2) 使用迭代器读取容器中的每一个数据元素,如:
vector vector (10,1);  //创建一个含有10个整型数1为元素的向量容器vector

//下面这条语句是将先前的10个数据元素分别改变为整型数2
for(vector::iterator iter=ivec.begin();iter!=ivec.end();++iter)
{
*iter=2;  //使用 * 访问迭代器所指向的元素
}
在STL中,对迭代器本身的基本操作如表3-1所示。

                     表3-1  对迭代器本身的基本操作
操作符	意  义
*	返回迭代器所指元素的值
++	将迭代器前进至下一个元素所在的位置
--	将迭代器退至上一个元素所在的位置
=	将某个元素的位置值赋给迭代器
==和!=	判断两个迭代器是否指向同一个位置
->	指向数据元素的某个字段域

(3) 各类容器都具有的两个最重要的成员函数
下面列出的两个函数是各类容器都具有的最重要的成员函数。在通过迭代器遍历容器的所有元素时要用到它们。
① begin()    让迭代器指向容器的第一个元素位置(如果有元素的话);
② end()      让迭代器指向容器最后一个元素之后的那个位置。
【例3-1】将LIST容器内的全部元素输出
#include 
#include 

using namespace std;
void main(){
    		list coll;      // list container for character elements
    		// append elements from 'a' to 'z'
    		for (char c='a'; c<='z'; ++c) {
       			 coll.push_back(c);
   		}

    		/* print all elements
     			* - iterate over all elements
     		*/
   		 list::const_iterator pos;  // const_iterator 指定pos 是一个“只读”迭代器
   		 for (pos = coll.begin(); pos != coll.end(); ++pos) {
        		cout << *pos << ' ';
   		 }
   		 cout << endl;
}
程序运行结果如图3-1所示。







图3-1  例3-1的运行结果

注:任何一种容器都可以定义三种类别的迭代器:
1、container::iterator
这种迭代器可以以“读/写”模式遍历容器诸元素,并且自身可以改变,例如:
for(vector:: iterator citer=ivec.begin();citer!=ivec.end();citer++)
{
cout<<*citer;  //ok(读)
*citer=3;      //ok(写)
}
2、container::const_iterator
这种迭代器只能以“读”模式遍历容器诸元素(元素值不可变),并且自身可以改变,例如:
for(vector::const_iterator citer=ivec.begin();citer!=ivec.end();citer++)
{    cout<<*citer;    //ok(读)
*citer=3;        //error(写)
}
因此,不妨将这种迭代器叫做“指向常量的迭代器”。
3、const container::iterator
这种迭代器可以以“读/写”模式遍历容器诸元素(元素值可变),但迭代器自身不可以改变,例如:
const vector::iterator newiter=ivec.begin();
*newiter=11;  //ok,可以修改指向容器的元素
newiter++;    // error,这种迭迭代器本身不能被修改 
因此,不妨将这种迭代器叫做“常迭代器”。
§3.2  迭代器的分类(Iterator Categorise)
     根据STL中的分类,iterator包括五类(注:这些类型的迭代器非独立于容器):
1、Input Iterator(输入迭代器):   输入迭代器也可以称之为前向的只读访问器,只
能单步向前迭代元素(即只提供++操作),不允许修改由该类迭代器引用的元素,只可以用来从序列中读取数据,如输入流迭代器。所有的容器的迭代器都具有输入迭代器的特征。
2、Output Iterator(输出迭代器):   输出迭代器也可以称之为前向的只写访问器,
该类迭代器和Input Iterator极其相似,也只能单步向前迭代元素(即只提供++操作),该类迭代器对元素只有写的能力,只允许向序列中写入数据,如输出流迭代器。
3、Forward Iterator(前向迭代器):   该类迭代器可以在一个正确的区间内进行读写
操作。它拥有Input Iterator的所有特性和Output Iterator的部分特性,以及单步向前迭代元素的能力。因此,它既是输入迭代器又是输出迭代器,并且只可以对序列进行前向的遍历。
4、Bidirectional Iterator(双向迭代器):该类迭代器是在Forward Iterator的基础上还提供了单步向后迭代元素的能力,在向前和向后两个方向上都可以对数据元素进行遍历。(即提供提供++操作,又提供--操作)。
5、Random Access Iterator(随机访问迭代器):   该类迭代器也是双向迭代器,它能够完成上面所有迭代器的工作。但它自己独有的特性就是可以像指针那样进行算术计算,能够在序列中的任意两个位置之间进行跳转。












图3-2  五种迭代器之间的关系

这五类迭代器的从属关系如图3-2所示,其中箭头B→A表示A是B的强化类型,也就是说如果一个算法要求B,那么A也可以应用于其中。例如,一个前向迭代器肯定是输入迭代器,也肯定是输出迭代器;再如,双向迭代器肯定是前向迭代器,等等。各类容器支持的迭代器的类别如表3-2所示。各类迭代器允许的算术操作情况参见表3-3。
§3.3  迭代器的算术操作
iterator除了表3-1列出的能进行++、--等操作外,还可以将iter+n、iter-n赋给一个新的iteraor对象。另外,还可以使用一个iterator减去另外一个iterator。表3-3列出了iterator允许的各种算术操作。例如:
const vector::iterator newiter=ivec.begin();  //注意迭代器 newiter自身不可改动
vector::iterator newiter2=ivec.end();        //newiter2迭代器可“读/写”
cout<<"\n"<p1	如果迭代器p的位置在p1后,返回true,否则返回false
		p>=p1	p的位置在p1的后面或同一位置时返回true,否则返回false
§3.4  迭代器的区间
STL算法的形参中常常包括一对输入迭代器,由它们构成容器数据元素的一个区间,该区间是容器数据元素的一个序列。STL算法常以迭代器的区间作为输入,传递输入数据,算法将在该区间上进行操作。
设p1和p2是两个输入迭代器,用[p1, p2)的形式表示它们构成容器数据元素的一个区间。该区间不包括p2所指向的那个元素,所以它是个半开区间。那么,若p1经过n次(n > 0)自增(++)操作后满足p1 == p2,区间[p1, p2)就是一个合法的区间。
【例3-2】
	#include 
#include 
#include 
using namespace std;

int main()
{
    		list coll;
    		list::iterator pos;

    		// insert elements from 20 to 40
    		for (int i=20; i<=40; ++i) {
        		coll.push_back(i);
    		}

   		 /* find position of element with value 3
     			* - there is none, so pos gets coll.end()
     		*/
   		 pos = find (coll.begin(), coll.end(),    // range
               			    3);                          // value
    
   		 /* reverse the order of elements between found element and the end
     			* - because pos is coll.end() it reverses an empty range
     		*/
    		reverse (pos, coll.end());

    		// find positions of values 25 and 35
    		list::iterator pos25, pos35;
   		 pos25 = find (coll.begin(), coll.end(),  // range
                  				25);                       // value
    		pos35 = find (coll.begin(), coll.end(),  // range
                  				35);                       // value

    		/* print the maximum of the corresponding range
     			* - note: including pos25 but excluding pos35
     		*/
    		cout << "max: " << *max_element (pos25, pos35) << endl;

    		// process the elements including the last position
    		cout << "max: " << *max_element (pos25, ++pos35) << endl;
}
运行结果如图3-3所示。







图3-3  例3-2运行结果

§3.5  迭代器的辅助函数
C++标准程序库为迭代器提供了advance()、distance()和Iter_swap()三个辅助函数。
§3.5.1  函数advance(p, n)
函数advance(p, n)的作用是让迭代器p前景或后退n个元素,即:
若p是输入型迭代器,则使迭代器p执行n次自增操作(n>0),表示让p前进n个元素;若p是输入型迭代器或随机访问型迭代器,则n可以取负值,表示让p后退n个元素。

    【例3-3】函数advance()的应用
	#include 
#include 
#include 

using namespace std;

int main(){
    	list coll;

    	// insert elements from 1 to 9
    	for (int i=1; i<=9; ++i) {
        	coll.push_back(i);  //在尾部插入元素
    	}

    	list::iterator pos = coll.begin();

    	// print actual element
    	cout << *pos << endl;
    	// step three elements forward
    	advance (pos, 3);

    	// print actual element
    	cout << *pos << endl;

    	// step one element backward
    	advance (pos, -1);

    	// print actual element
   		cout << *pos << endl;
}
运行结果如图3-4所示。

    






图3-4  例3-3运行结果

§3.5.2  函数distance(first, last)
函数distance(first, last)的作用是计算两个迭代器first和last之间的距离。即当first
#include 
#include 
using namespace std;

int main(){
    	list coll;

    	// insert elements from -3 to 9
    	for (int i=-3; i<=9; ++i) 
        	coll.push_back(i);
   
    	// search element with value 5
    	list::iterator pos;
    	pos = find (coll.begin(), coll.end(), 5);                         
    	if (pos != coll.end()) 
        	// process and print difference from the beginning
        	cout << "difference between beginning and 5: "
             	<< distance(coll.begin(),pos) << endl;
        else 
        	cout << "5 not found" << endl;
    }
	运行结果如图3-5所示。
	





图3-5  例3-4运行结果

§3.5.3  函数Iter_swap(p1,p2)
函数Iter_swap(p1,p2)的作用是交换迭代器p1和p2所指数据元素的值。

【例3-5】函数Iter_swap()的应用
#include 
#include 
#include 
using namespace std;

/* PRINT_ELEMENTS()是一个泛型函数,可以打印一个字符串(也可以不指定),然后打印容器的全部元素。容器名提供给第一个参数;第二个参数是可有可无的前缀字,用来在打印时放在所有元素之前。
*/
template 
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
    typename T::const_iterator pos;

    std::cout << optcstr;
    for (pos=coll.begin(); pos!=coll.end(); ++pos) {
        std::cout << *pos << ' ';
    }
    std::cout << std::endl;
}  

int main()
{
    list coll;

    // insert elements from 1 to 9
    for (int i=1; i<=9; ++i) 
        coll.push_back(i);

    PRINT_ELEMENTS(coll);

    // swap first and second value
    iter_swap (coll.begin(), ++coll.begin());

    PRINT_ELEMENTS(coll);

    // swap first and last value
    iter_swap (coll.begin(), --coll.end());

    PRINT_ELEMENTS(coll);
}
运行结果如图3-6所示。








图3-6  例3-5运行结果

§3.6 迭代器适配器(Iterator Adapters)
C++标准程序库提供了数个预先定义的特殊迭代器,称为迭代器适配器(Iterator  Adapters)。如Insert Iterators(安插型迭代器)、Stream Iterators(流迭代器)、Reverse Iterators(逆向迭代器)。
§3.6.1  Insert Iterators(安插型迭代器)
安插型迭代器可以使算法以插入(insert)方式而非覆盖(overwrite)方式动作。同时,它会使目标空间的大小按需要成长。有如下三种预定义好的安插型迭代器:
①back_inserter(安插于容器的最尾端)
这是一个追加动作,它只适用于具有push_back()成员函数的vector、deque和list三种容器。
②front_inserter(安插于容器的最前端)
元素的安插位置与安插顺序相反。它只适用于具有push_front()成员函数的deque和list两种容器。
③inserter(一般性安插器)
它的作用是将元素插入到“初始化时接收的第二个参数”所指位置的前方。它主要用于关联式容器。
【例3-6】
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){
    list coll1;
list::iterator pos1;

    for (int i=1; i<=9; ++i)    // insert elements from 1 to 9 into the first collection
        coll1.push_back(i);
    
     cout<<"List:"< coll2;
    vector::iterator pos2;
    copy (coll1.begin(), coll1.end(),      // source
          back_inserter(coll2));       // destination
cout<<"vector:"< coll3;
deque::iterator pos3;
    copy (coll1.begin(), coll1.end(),      // source
          front_inserter(coll3));       // destination

cout<<"Deque:"< coll4;
set::iterator pos4;
    copy (coll1.begin(), coll1.end(),      // source
          inserter(coll4,coll4.begin()));  // destination
	cout<<"Set:"<。
流迭代器包括istream_iterator(输入流迭代器)和ostream_iterator(输出流迭代器)。istream_iterator是用来从input stream流对象中连续读取指定的某种类型的数据元素。ostream_iterator是用来向output stream流对象中连续写入指定的某种类型的数据元素。
1、ostream_iterator
ostream_iterator将赋值操作转化为对输出运算符“<<”的操作。ostream_iterator类的构造函数如下:
ostream_iterator(ostream):   为ostream(输出流)产生一个ostream_iterator
ostream_iterator(ostream, delim):为ostream(输出流)产生一个ostream_iterator,各元素间以delim为分隔符(注意,delim的数据类型是const char*,即字符串)。
产生ostream_iterator对象时,必须提供一个output stream流对象(通常是“cout”)作为参数,ostream_iterator将会把要输出的元素值写到output stream流对象上,如“cout”上。另一个参数delim可有可无。
2、istream_iterator
istream_iterator将赋值操作转化为对输出运算符“>>”的操作。istream_iterator类的构造函数如下:
istream _iterator():   缺省构造函数将产生一个end-of-stream迭代器。判定输入是否结束。
istream _iterator( istream):为istream(输入流)产生一个istream_iterator对象(可能立刻读取第一个元素)。
产生istream _iterator对象时,必须提供一个intput stream流对象(通常是“cin”)作为参数。
【例3-7】从键盘输入两个字符串:“aaaaaa”和“bbbbbb”,然后输出出来。
#include 
#include 
#include 
#include 
#include    //使用独立于容器的迭代器时,必须包含该头文件
using namespace std;

int main(){
    vector coll;

    /* read all words from the standard input
     * - source: all strings until end-of-file (or error)
     * - destination: coll (inserting)
     */
    copy (istream_iterator(cin),     // start of source
          istream_iterator(),       // end of source
          back_inserter(coll));             // destination

    // sort elements
    sort (coll.begin(), coll.end());  //对所有元素排序

    /* print all elements without duplicates
     * - source: coll
     * - destination: standard output (with newline between elements)
     */
    unique_copy (coll.begin(), coll.end(),             // source
                 ostream_iterator(cout,"\n")); // destination
}
程序运行结果如图3-8 所示。









图3-8   例3-7运行结果

对【例3-7】做几点解释:
1、对下面这条copy语句中的三个参数解释如下:
copy (istream_iterator(cin),   istream_iterator(), back_inserter(coll)); 
①istream_iterator(cin)—用cin作为参数,调用istream_iterator的有参构造函数,生成一个istream_iterator迭代器。模板参数string表示生成的这个迭代器专门用于读取该类型的元素。因此,istream_iterator(cin)是从标准输入流对象cin连续读取字符串;
②istream_iterator()--调用istream_iterator的缺省构造函数,产生一个代表"流结束符号"的迭代器,它代表的含义是不能再从输入流中读取任何东西,实际上,它是输入的终点,即用作输入区间的终点;
③back_inserter(coll)——借助它将读取到的数据拷贝并插入到容器coll中。

2、下面这条语句:
  unique_copy (coll.begin(), coll.end(), 
                 ostream_iterator(cout,"\n"));
①算法unique_copy()的作用是将coll容器中的所有元素拷贝到目的端cout,处理过程中算法unique_copy()会消除比邻的重复值;
②ostream_iterator(cout,"\n")——调用有参构造函数生成一个输出流迭代器对象,并指定模板参数类型为string。"\n"的作用是指元素之间的分隔符是换行(还可以是其它的分隔符,如“\t”或“  ”等)。
§3.6.3  Reverse Iterators(逆向迭代器)
reverse Iterators(逆向迭代器)的作用是以逆向方式进行所有操作,即将递增运算转换为递减运算,将递减运算转换为递增运算。所有容器都可以通过其成员函数rbegin()和rend()产生reverse Iterators。
【例3-8】
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
   	vector coll;

    	 	// insert elements from 1 to 9
    	 	for (int i=1; i<=9; ++i) {
         		coll.push_back(i);
    		}

    		// print all element in reverse order
    		copy (coll.rbegin(), coll.rend(),        // source
          		ostream_iterator(cout," "));  // destination
   	 	cout << endl;
}
程序运行结果如图3-9 所示。

    





图3-9   例3-8运行结果

对【例3-8】的说明:
表达式coll.rbegin()返回一个由coll定义的reverse Iterators,并将其作为“对coll逆向遍历”的起点。它指向coll的尾部(最后一个元素的下一位置)。因此,*coll.rbegin()表达式返回的是最后一个元素的值。

同样,coll.rend()也返回一个由coll定义的reverse Iterators,并将其作为“对coll逆向遍历”的终点。它指向coll内第一个元素的前一个位置。





第4讲  STL函数对象

每当提到C++ STL,首先被人想到的是它的三大核心组件:Containers, Iterators以及Algorithms,即容器,迭代器和算法。容器为用户提供了常用的数据结构,算法是独立于容器的常用的基本算法,迭代器是由容器提供的一种接口,算法通过迭代器来操控容器。其实C++ STL还有另外一种重要组件,即函数对象(Function Object r)。函数对象又称为仿函数(functor)。STL中有很多算法(这些算法包含在algorithm头文件中)都需要为它提供一个称之为函数对象类型的参数。
其实,有关函数对象的内容在第1讲里已经讨论了一些,本讲继续介绍函数对象的概念,重点介绍STL中预定义的函数对象及其用法。
程序中使用STL预定义的函数对象,首先需要包含头文件:#include 。
§4.1  什么是函数对象
所谓函数对象其实就是一个行为类似函数的“东西”,它可以没有参数,也可以带有若干参数,其功能是获取一个值,或者改变操作的状态。在C++程序设计中,任何普通函数和任何重载了函数调用运算符“()”的类的实例都是函数对象,都可以作为参数传递给STL算法。
 下面以STL算法中的accumulate()算法为例,介绍函数对象的设计与应用过程。算法accumulate()的函数模版原型如下:

下面使用两种方式定义表示数组元素乘法的函数对象,见例4-1和例4-2。

【例4-1】通过定义普通函数来定义函数对象
一般来说,用户设计的普通函数就是一种最简单的函数对象。本例首先设计一个普通的函数mult()作为函数对象传递给算法accumulate()。 
#include    
#include 	//使用accumulate()算法必须包含数值算法头文件
using namespace std;

//定义一个普通函数作为函数对象传递给算法accumulate(),进行累积运算
int mult(int x, int y)  { return x * y; };	

int main() {     //测试函数
	int a[] = { 1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);  //求a的元素个数
	cout << "数组a的元素乘积= "
		<< accumulate(a, a + N, 1, mult)  //全局普通函数 mult作为函数对象
		<< endl;
	return 0;
}
程序运行结果如图4-1所示。






图4-1

【例4-2】通过类来定义函数对象
#include    
#include 	//使用accumulate()算法必须包含数值算法头文件
using namespace std;

class MultClass { 
public:
	int operator() (int x, int y) const  { return x * y; }	//必须重载operator()函数
};

int main() {      //测试函数
	int a[] = { 1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);  //求a的元素个数
	cout << "数组a的元素乘积= "
	<< accumulate(a, a + N, 1, MultClass()) //调用默认构造函数生成临时匿名对象
		<< endl;
	return 0;
}
程序运行结果也如图4-1所示。

下面再举一个例子(【例4-3】),以便进一步理解通过类来定义函数对象的方法。
【例4-3】求整形向量各元素之和(即计算)
#include
#include
#include 
#include
using namespace std;

class CSum
{
private:
int sum;
public:
CSum()  {sum = 0;}     //构造函数
void operator()(int n)        //必须重载operator()函数
{
sum += n;
}
int GetSum()  {return sum;}
};

void main(){
vector v ;
for(int i=1; i<=100; i++)
{  v.push_back(i); }
CSum sObj = for_each(v.begin(), v.end(), CSum()); 
/*在上面一条语句中,由默认构造函数生成一个匿名临时函数对象。算法for_each()是对给定的区间内每一个数据元素执行函数对象CSum(),即执行operator()函数 */

cout<。
标准C++库根据重载的operator()函数的参数个数是0个,1个或2个而将STL预定义的仿函数划分为以下几种类型,它们之间的关系如图4-3所示:
发生器(Generator):没有参数且返回一个任意类型值的函数对象,例如随机数发生器。
一元函数(Unary Function):只有一个任意类型的参数,且返回一个可能不同类型值的函数对象。
二元函数(Binary Function):有两个任意类型的参数,且返回一个任意类型值的函数对象。
一元谓词(Unary Predicate):返回bool型值的一元函数。一元谓词又叫做一元判定函数。
二元谓词(Binary Predicate):返回bool型值的二元函数。二元谓词又叫做二元判定函数。
可以看出,STL中函数对象最多仅适用于两个参数的情况(无参数、一元或二元情况),但这也足以完成相当强大的功能。

表4-1  STL预定义的仿函数(仅一个一元仿函数)
	仿  函  数 名 称	类型	结果描述
算术类
函数对象	加法:plus()	二元函数	arg1 + arg2
	减法:minus()	二元函数	arg1 - arg2
	乘法:multiples()	二元函数	arg1 * arg2
	除法:divides()	二元函数	arg1 / arg2
	模取:modules()	二元函数	arg1 % arg2
	否定:negate()	一元函数	-arg
关系运算类
函数对象	等同:equal_to()	二元函数	arg1 == arg2
	不等于:not_equal_to()	二元函数	arg1  !=  arg2
	大于:greater()	二元函数	arg1 > arg2
	大于等于:greater_equal()	二元函数	arg1 >= arg2
	小于:less()	二元函数	arg1 < arg2
	小于等于:less_equal()	二元函数	arg1 <= arg2
逻辑运算类
函数对象	与:logical_and()	二元函数	arg1 && arg2
	或:logical_or()	二元函数	arg1 || arg2
	非: logical_not()	二元函数	!arg1












图4-3  函数对象的关系

要特别注意使用表4-1个列出的STL预定义仿函数(它们都是继承于§4.3介绍的两个基类的子类)的方法:
方法一:先产生函数对象实例,然后运用该实例执行函数功能,如:
        plus plusobj;            //先产生函数对象plus的实例plusobj
        cout<< plusobj (2,4)<() (2,4)<()同样可以实现例4-1或例4-2对元素连乘的操作。
#include    
#include    //包含数值算法头文件
#include   //包含标准函数对象头文件
using namespace std;	
int main() {
	int a[] = { 1, 2, 3, 4, 5 };
	const int N = sizeof(a) / sizeof(int);

     //在下面的语句中将标准二元函数对象multiplies()传递给通用算法
	cout << "数组a的元素乘积= "
		<< accumulate(a, a + N, 1, multiplies())<< endl;
	return 0;
}
本程序运行结果也如同图4-1所示。

说明:对于常规通用数据类型char、int、float、double、string而言,可以直接套用STL预定义的基本函数对象,如上面介绍的两种方法。但对于非常规数据类型(如复数类型),则必须在定义该类型的类(如复数类)内重载相应的运算符。关于这方面的例子请参考有关书籍,下同。

二、STL预定义的关系运算类(一元谓词和二元谓词)函数对象使用示例
它们都返回bool型,因此,它们都是谓词。同样,也要注意它们的使用方法。

【例4-5】此例将二元函数对象greater()带入sort()算法,从而实现把一个数组降序排列。默认情况下,sort()算法使用less比较器进行比较,实现的是升序排列。
#include 
#include 
#include 
#include 
#include 
using namespace std;
int main(){
	int intArr[] = { 30, 90, 10, 40, 70, 50, 20, 80 };
	const int N = sizeof(intArr) / sizeof(int);
	vector a(intArr, intArr + N);

	cout << "before sorting:" << endl;
	copy(a.begin(), a.end(), ostream_iterator(cout, "\t"));
	cout << endl;

	sort(a.begin(), a.end(), greater());  //降序排列

	cout << "after sorting:" << endl;
	copy(a.begin(), a.end(), ostream_iterator(cout, "\t"));
	cout << endl;
	return 0;
}
运行结果如图4-4所示。

图4-4  例4-5运行结果

三、STL预定义的逻辑运算类(一元谓词和二元谓词)函数对象使用示例
【例4-6】
#include 
#include 
using namespace std;
void main(){
	//产生一些函数对象实体
logical_andandobj;
logical_ororobj;
logical_notnotobj;

//运行上述对象执行函数功能
cout<()(3<5,6<9)<()(3<5,6>9)<()(3<5)<
    struct unary_function
{
typedef _A argument_type;     
    	typedef _R result_type;
    };

它有两个模板参数,_A是输入参数,_R是返回值类型,且此两个参数的类型是任意的,因此,它的动态特性非常强。 

【例4-7】设计一个一元函数对象对向量各元素进行处理
#include 
#include 
#include 
#include 
using namespace std;

void Add(int & ri)  //普通全局函数
{
     		ri += 5;
 	}
class Sub : public unary_function //通常必需继承自基类unary_function
 	{
		public:
     			void operator() (int & ri)
     			{
         			ri -= 5;   // ri = ri - 5
     			}
 	};

 	void main()
{
     		int a[10]={0,1,2,3,4,5,6,7,8,9};
     		copy(a,a+10,ostream_iterator(cout,"  "));
     		cout << endl;

     		for_each(a,a+10,Add);  //普通全局函数Add作为函数对象传给算法for_each
     		copy(a,a+10,ostream_iterator(cout,"  "));
     		cout << endl;

     		for_each(a,a+10,Sub());   //通过Sub类默认构造函数生成临时匿名对象
     		copy(a,a+10,ostream_iterator(cout,"  "));
     		cout << endl;
}
程序运行结果如图4-5所示。








图4-5  例4-7运行结果

二、二元函数对象
基类binary__function的类模板原型如下:

template
    struct binary_function
{
    		typedef Arg1 first_argument_type;
    		typedef Arg2 second_argument_type;    		
typedef Result result_type;
    };	 

它有三个模板参数,Arg1、Arg2是输入参数,Result是返回值类型,且此三个参数的类型是任意的,因此,它的动态特性非常强。 

【例4-8】设计一个二元函数对象binary_sort,实现对向量元素升序排列
#include 
#include 
#include 
#include 
#include 
using namespace std;

class Student
{
public:
	string name;
	int grade;

	Student(string name1,int grade1)
	{
		name=name1;
		grade=grade1;
	}

	bool operator<(const Student &s) const
	{
		return grade
class binary_sort:public binary_function<_inPara1,_inPara2,bool>
{
public:
	bool operator()(_inPara1 in1,_inPara2 in2)
	{
		return in1 v;
	v.push_back(s1);
	v.push_back(s2);
	v.push_back(s3);
	v.push_back(s4);
	sort(v.begin(),v.end(),binary_sort());  //按升序排列
	copy(v.begin(),v.end(),ostream_iterator(cout,"   "));  //升序结果输出
}
程序运行结果如图4-6所示。









图4-6  例4-8运行结果

说明:该函数的程序执行流程:
主程序中首先把4个学生对象依次放入向量v中,当执行排序函数sort时,调用二元函数类binary_sort中重载的operator()函数,当执行函数体in1中。
表4-2列出了STL提供的函数适配器(它们也是类模版),分为如下4大类:
●  绑定适配器——将n元函数对象的指定参数绑定为一个常数,得到n-1元函数对象;●  取反适配器——将指定谓词的结果取逻辑反;
●  指针函数适配器——对一般函数指针使用,使之能够作为其它函数适配器的输入;
●  成员函数适配器——对成员函数指针使用,把n元成员函数适配为n + 1元函数对象,该函数对象的第一个参数为调用该成员函数时的目的对象。

表4-2  STL提供的函数适配器
类  型	STL提供的函数适配器	功 能 说 明
绑定
适配器	binder1st	将数值帮定到二元函数的第一个参数,适配成一元函数
	binder2nd	将数值帮定到二元函数的第二个参数,适配成一元函数
取反
适配器	unary_negate	将一元谓词的返回值适配成其逻辑反
	binary_negate	将二元谓词的返回值适配成其逻辑反
指针函数
适配器	pointer_to_unary_function	将普通一元函数指针适配成unary_function
	pointer_to_binary_function	将普通二元函数指针适配成binary_function
表4-2(续)
                                                      成员函数
适配器	mem_fun_t	将无参数类成员函数适配成一元函数对象,第一个参数为该类的指针类型
	mem_fun_ref_ t	将无参数类成员函数适配成一元函数对象,第一个参数为该类的引用类型
	mem_fun1_t	将单参数类成员函数适配成二元函数对象,第一个参数为该类的指针类型
	mem_fun1_ref_ t	将单参数类成员函数适配成二元函数对象,第一个参数为该类的引用类型
	const_mem_fun_t	将无参数类常成员函数适配成一元函数对象,第一个参数为该类的常指针类型
	const_mem_fun_ref_ t	将无参数类常成员函数适配成一元函数对象,第一个参数为该类的常引用类型
	const_mem_fun1_t	将单参数类成员函数适配成二元函数对象,第一个参数为该类的常指针类型
	const_mem_fun1_ref_ t	将单参数类成员函数适配成二元函数对象,第一个参数为该类的常引用类型

为了简化函数适配器的构造,STL还提供了若干函数适配器辅助函数(如表4-3所示)。通过这些函数适配器辅助函数可以直接地、隐式实现函数适配器的构造,无须通过函数适配器(是类)的构造函数来构造函数适配器的实例(否则书写其代码很麻烦),从而大大简化或根本不用书写构造函数适配器的代码。

表4-3  STL函数适配器辅助函数
函  数	功  能  说   明
bind1st()	辅助构造binder1st适配器实例,帮定固定值到二元函数的第一个参数位置
bind2nd()	辅助构造binder2st适配器实例,帮定固定值到二元函数的第二个参数位置
not1()	辅助构造unary_negate适配器实例,生成一元函数的逻辑反函数
not2()	辅助构造binary_negate适配器实例,生成二元函数的逻辑反函数
mem_fun()	辅助构造mem_fun_t等成员函数适配器实例,返回一元或二元函数对象
mem_fun_ref()	辅助构造mem_fun_ ref等成员函数适配器实例,返回一元或二元函数对象
ptr_fun()	辅助构造一般全局函数指针的pointer_to_unary_function
或pointer_to_binary_function适配器实例

下面分别介绍几种函数适配器辅助函数的基本用法。
一、绑定、取反适配器
【例4-9】绑定、取反适配器基本用法
#include 
#include 
#include 

using namespace std;

void main(){
	int a[] = {1,3,5,7,9,8,6,4,2,0};
	int nCount = count_if(a, a+sizeof(a)/sizeof(int), bind2nd(less(), 4));
	cout << nCount << endl;		//输出4

	nCount = count_if(a, a+sizeof(a)/sizeof(int), bind1st(less(), 4));
	cout << nCount << endl;		//输出5

	nCount = count_if(a, a+sizeof(a)/sizeof(int), not1(bind2nd(less(), 4)));
	cout << nCount << endl;		//输出6

	nCount = count_if(a, a+sizeof(a)/sizeof(int), not1(bind1st(less(), 4)));
	cout << nCount << endl;		//输出5

	sort(a, a+sizeof(a)/sizeof(int), not2(less()));

    //下面的语句输出9 8 7 6 5 4 3 2 1 0
copy(a, a+sizeof(a)/sizeof(int), ostream_iterator(cout, " ")); 
   cout << endl;	
}
注:针对【例4-8】着重理解以下的知识点:
(1)bind2nd(less(),4)):
less()本身是一个二元函数对象,相当于普通函数bool less(T x,T y){ return x(),4))相当于普通函数bool less(T x, int n=4){return x<4},bind2nd的作用是使less二元函数的第二个参数绑定为整形4。因此,相当于把二元函数降低为一元函数,count_if语句中是求数组a中小于4的数据个数是多少,可知符合条件的数有{1,3,2,0},共4个。
(2)bind1st(less(),4): 
less()本身是一个二元函数对象,相当于普通函数bool less(T x,T y){ return x(),4))相当于普通函数bool less(int n=4, T x){return 4(), 4)):
 bind2nd(less(), 4)相当于普通函数bool less(T x, int n=4){return x<4;},not1后,相当于bool less(T x, int n=4){return !(x<4);},语义上相当于“不小于4”,即求不小于4的数据个数是多少,可知符合条件的数有{5,7,9,8,6,4},共有6个。
(4)not1(bind1st(less(), 4)): 
bind1st(less(), 4)相当于普通函数bool less(int n=4, T x){return 4()): 
less()相当于普通函数bool less(T x, T y){return x
#include 
#include 
#include 
using namespace std;

class Person
{
	public:
		Person(string init)
		{
			name=init;
		}
		string name;
};

bool  shorter (const Person & t1, const Person & t2)  //普通全局函数
{
    Return  t1.name.length() < t2.name.length();
}

void main()
{
    vector iv;
    iv.push_back(Person("one"));
    iv.push_back(Person("two"));
    iv.push_back(Person("three"));
    iv.push_back(Person("four"));

    //将函数指针(函数名即是)传递进去
    sort(iv.begin(), iv.end(), shorter);  // shorter函数作为函数对象

    for (vector::iterator it = iv.begin(); it != iv.end(); ++it)
       cout << (*it).name << "   ";
    cout<
#include 
#include 
#include 
#include 
using namespace std;

class Student
{
		string strNO;     //学号
		string strName;   //姓名
	public:
		Student(string strNO1, string strName1)
		{
			strNO=strNO1;
			strName=strName1;
		}
		bool show()      //学生信息显示成员函数(类的普通成员函数)
		{
			cout< v;
	v.push_back(s1);
	v.push_back(s2);
	for_each(v.begin(),v.end(),mem_fun_ref(Student::show));
	cout< pv;
	pv.push_back(ps1);
	pv.push_back(ps2);
	for_each(pv.begin(),pv.end(),mem_fun(Student::show));
	cout<,则用mem_fun_ref;若集合是基于对象指针的,形如vector,则用mem_fun。
(2)以下调用写法是错误的:
for_each(v.begin(), v.end(), Student::show), 当在STL算法中调用成员函数时,一般要通过mem_fun_ref或mem_fun转换后才可以应用。

§4.5  STL预定义函数对象应用示例
C++标准库定义了几个有用的函数对象,它们被放到STL算法中。例如,sort()算法以判断对象(predicate object)作为其第三个参数。判断对象是一个返回Boolean型结果的模板化的函数对象。可以向sort()传递判断函数对象greater<>或者less<>来强行实现降序排序或升序排序:

#include 
#include   // for greater<> and less<>
#include   //for sort() 
#include 
using namespace std;

int main(){ 
vector  coll;  //生成一个元素是int类型的向量容器coll
//..填充向量	
    coll.push_back(2);
   	coll.push_back(5);
    coll.push_back(4);
   	coll.push_back(1);
    coll.push_back(6);
    coll.push_back(3);
        cout << "向量中元素的初始顺序:"<());  //降序( descending )
cout << "向量中元素降序排序的结果:"<());     //升序 ( ascending )
cout << "向量中元素升序排序的结果:"<,,组成。在使用 STL中的算法(函数)之前,首先必须包含头文件。对于数值算法须包含头文件。头文件中定义了一些模板类,用来声明函数对象。
   
注意,算法并非容器的成员函数,而是一种全局的泛型函数,无需通过容器对象调用它们,直接使用即可。还要注意,有些算法和容器的某些成员函数具有相同的功能。
下面首先介绍for_each()算法:
for_each()算法非常灵活,它可以以不同的方式存取、处理、修改每一个数据元素。

UnaryProc for_each (InputIterator beg, InputIterator end, 
UinaryPredicate op)

    ●其功能是对区间中的每一个元素调用:op(elem) 

下面列举三个示例展示for_each()算法的使用。先设计一个头文件algostuff.hpp如下:
//algostuff.hpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* PRINT_ELEMENTS()
 * - prints optional C-string optcstr followed by
 * - all elements of the collection coll
 * - separated by spaces
 */
template 
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
    typename T::const_iterator pos;

    std::cout << optcstr;
    for (pos=coll.begin(); pos!=coll.end(); ++pos) {
        std::cout << *pos << ' ';
    }
    std::cout << std::endl;
}

/* INSERT_ELEMENTS (collection, first, last)
 * - fill values from first to last into the collection
 * - NOTE: NO half-open range
 */
template 
inline void INSERT_ELEMENTS (T& coll, int first, int last)
{
    for (int i=first; i<=last; ++i) {
        coll.insert(coll.end(),i);
    }
}

【示例1】将print()传给for_each(),使得for_each()对每一个元素调用print(),从而输出所有元素:
//foreach1.cpp 
#include "algostuff.hpp"
using namespace std;

// function called for each element
void print (int elem)
{
    cout << elem << ' ';
}

int main(){
    vector coll;

    INSERT_ELEMENTS(coll,1,9);

    // call print() for each element
    for_each (coll.begin(), coll.end(),  // range
              print);                // operation
    cout << endl;
}
程序输出结果如下:
             1  2  3  4  5  6  7  8  9

【示例2】利用仿函数改变每一个元素的内容:
/foreach2.cpp
#include "algostuff.hpp"
using namespace std;

// function object that adds the value with which it is initialized
template 
class AddValue {
  		private:
    			T theValue;    // value to add
  		public:
    			// constructor initializes the value to add
    			AddValue (const T& v) : theValue(v) { }

   			 // the function call for the element adds the value
    			void operator() (T& elem) const {
        			elem += theValue;
    			}
};

int main(){
    		vector coll;

    		INSERT_ELEMENTS(coll,1,9);

   		 // add ten to each element
   		 for_each (coll.begin(), coll.end(),       // range
              			AddValue(10));             // operation
    		PRINT_ELEMENTS(coll);

    		// add value of first element to each element
    		for_each (coll.begin(), coll.end(),       // range
              		AddValue(*coll.begin()));  // operation
    		PRINT_ELEMENTS(coll);
}
 	程序输出如下:
11 12 13 14 15 16 17 18 19
22 23 24 25 26 27 28 29 30
Press any key to continue

【示例3】利用的返回值。由于能够返回一项操作,所以可以在该项操作中处理返回结果:
//foreach3.cpp
#include "algostuff.hpp"

using namespace std;

// function object to process the mean value
class MeanValue {
  		private:
    			long num;    // number of elements
    			long sum;    // sum of all element values
  		public:
    			// constructor
    			MeanValue () : num(0), sum(0) {
   			 }

    			// function call
   			// - process one more element of the sequence
    			void operator() (int elem) {
        			num++;          // increment count
        			sum += elem;    // add value
    			}

    			// return mean value (implicit type conversion)
    			operator double() {
       	 			return static_cast(sum) / static_cast(num);
    	}
};

int main()
{
    		vector coll;

   	 	INSERT_ELEMENTS(coll,1,8);

    		// process and print mean value
    		double mv = for_each (coll.begin(), coll.end(),  // range
                          MeanValue());              // operation
    		cout << "mean value: " << mv << endl;
}
程序输出如下:
mean value: 4.5
Press any key to continue
§5.1  非变异算法
非变异算法是一组不破坏操作数据元素的模板函数,用来对序列数据元素进行逐个处理、元素查找、子序列搜索、统计和匹配。非变异算法具有极为广泛的适用性,基本上可应用于各种容器。表5-1列出了主要的非变异算法。

表5-1   主要的非变异算法
序号	功能	函数名称	说       明
1	循环	for_each()	遍历容器元素,对每个元素都执行某操作
2	查询	find()	找出等于某个值的第一次出现的那个元素的位置
		find_if()	找出符合某谓词的第一个元素的位置
		find_first_of()	找出等于“某数个值之一”的第一次出现的元素
		adjacent_find()	找出第一次相邻值相等的元素
		find_end()	找出一子序列的最后一次出现的位置
		search()	找出某一子区间第一次出现的位置
		search_n	找出某特定值连续n次出现的位置
3	计数	count()	统计某个值出现的次数
		count_if()	统计与某谓词(表达式)匹配的元素个数
4	比较	equal()	判断是否相等,即两个序列中的对应元素都相同时为真
		mismatch()	找出两个序列第一个相异的元素
		min_element()	返回最小值元素的位置
		max_element()	返回最大值元素的位置

下面通过示例对部分常用的非变异算法加以说明,以加深对它们的功能与用法的理解:
1、查找容器元素位置算法find()
【功能】:它用于查找等于某值的第一个出现的那个元素。

形式1:InputIterator  find(InputIterator beg, InputIterator end, const T & value)


形式2:InputIterator  find_if(InputIterator beg, InputIterator end, 
UinaryPredicate op)

形式1返回迭代器区间[beg,end)中第一个“元素值等于value”的元素位置,即如果迭代器i所指的元素满足*i=value,则返回迭代器i;未找到满足条件的元素,返回end。
形式2返回迭代器区间[beg,end)中使一元判别式op(elem)为true的第一个元素;未找到返回end。

【例5-1】 
#include 
#include 
#include 
using namespace std;

void main(){
  int num_to_find = 6;            
  vector v1; 
  for( int i = 0; i < 10; i++ ) 
      v1.push_back(2*i);               
  vector::iterator result; 

  result = find( v1.begin(), v1.end(), num_to_find );
   if( result == v1.end() ) 
      cout << "未找到任何元素匹配 " << num_to_find << endl;                
  else 
      cout << "匹配元素的索引值是 " << result - v1.begin() << endl;
}
运行结果如图5-1所示。

       




图5-1  例5-1运行结果

2、条件查找容器元素位置算法find_if()
【功能】:在迭代器区间[beg,end )上,找出符合某谓词的第一个元素的位置;未找到元素,返回末位置end。
【例5-2】在已经出现过。
#include 
#include 
#include 
using namespace std;

bool divby5(int x)
{
    return x%5?0:1; //若x能被5整除返0,否则返1                                                    
}

void main(){
   vector v(20);
   for(int i=0;i::iterator ilocation;
   
ilocation=find_if(v.begin(),v.end(),divby5);
  
 if(ilocation!=v.end())
   cout<<"找到第一个能被5整除的元素:"<<*ilocation
   <::difference_type
● 关联式容器(sets,multisets,maps和multimaps)提供了一个等效的成员函数count(),用来计算等于某个value或某个key的元素个数。
【例5-3】元素计数算法示例。先给出头文件algostuff.hpp如下:
 //algostuff.hpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* PRINT_ELEMENTS()
 * - prints optional C-string optcstr followed by
 		 * - all elements of the collection coll
 		 * - separated by spaces  */
template 
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
    			typename T::const_iterator pos;

    			std::cout << optcstr;
    			for (pos=coll.begin(); pos!=coll.end(); ++pos) {
        			std::cout << *pos << ' ';
    			}
    			std::cout << std::endl;
}
/* INSERT_ELEMENTS (collection, first, last)
 		* - fill values from first to last into the collection
 		* - NOTE: NO half-open range
 		*/
template 
inline void INSERT_ELEMENTS (T& coll, int first, int last)
{
    			for (int i=first; i<=last; ++i) {
        			coll.insert(coll.end(),i);
    				}
}
下面的范例程序是根据不同的准则对元素进行计数:
    // count1.cpp
    #include "algostuff.hpp"
using namespace std;

bool isEven (int elem)
{  return elem % 2 == 0;  }

int main(){
    		vector coll;
    		int num;

    		INSERT_ELEMENTS(coll,1,9);
    		PRINT_ELEMENTS(coll,"coll: ");

    		// count and print elements with value 4
    		num = count (coll.begin(), coll.end(),       // range
                 				 4);                             // value
    		cout << "number of elements equal to 4:      " << num << endl;

    		// count elements with even value
    		num = count_if (coll.begin(), coll.end(),    // range
                    				 isEven);                     // criterion
    		cout << "number of elements with even value: " << num << endl;

    		// count elements that are greater than value 4
    		num = count_if (coll.begin(), coll.end(),    // range
                    			bind2nd(greater(),4));  // criterion
    		cout << "number of elements greater than 4:  " << num << endl;
}
本程序运行结果如下图5-3所示:









图5-3  例5-3运行结果

4、求最大值和求最小值元素位置算法max_element()算法和min_element()
   
   形式1:InputIterator max_element (InputIterator beg, InputIterator end)


形式2:InputIterator max_element (InputIterator beg, InputIterator end, 
CompFunc op)

形式3:InputIterator min_element (InputIterator beg, InputIterator end)


形式4:InputIterator min_element (InputIterator beg, InputIterator end, 
CompFunc op)

●所有这些算法都返回区间[beg,end)中最大或最小元素的位置;
●op用来比较两个元素:op(elem1,elem2),如果elem1
#include "algostuff.hpp"
using namespace std;

bool absLess (int elem1, int elem2)
{
    		return abs(elem1) < abs(elem2);
}

int main(){
    		deque coll;

    		INSERT_ELEMENTS(coll,2,8);
    		INSERT_ELEMENTS(coll,-3,5);

    		PRINT_ELEMENTS(coll);

    		// process and print minimum and maximum
    		cout << "minimum: "
         		<< *min_element(coll.begin(),coll.end())<< endl;
    		cout << "maximum: "
         		<< *max_element(coll.begin(),coll.end())<< endl;

    		// process and print minimum and maximum of absolute values
    		cout << "minimum of absolute values: "
         			<< *min_element(coll.begin(),coll.end(),absLess)<< endl;
    			cout << "maximum of absolute values: "
         				<< *max_element(coll.begin(),coll.end(),absLess)<< endl;
}
程序运行结果如图5-4所示:









图5-4  例5-4运行结果

5、子序列搜索算法search()
【功能】:在一个序列中搜索与另一序列匹配的子序列首位置

形式1:ForwardIterator1 search (ForwardIterator1 beg, ForwardIterator1 end
ForwardIterator2 searchBeg, ForwardIterator2 searchEnd)


形式2:ForwardIterator1 search (ForwardIterator1 beg, ForwardIterator1 end
ForwardIterator2 searchBeg, ForwardIterator2 searchEnd, BinaryPredicate op)

●两种形式都返回区间[beg,end)内和区间[searchBeg , searchEnd)内完全吻合的第一个子区间内的第一个元素位置;
●形式1中,子区间的元素必须完全等于[searchBeg, searchEnd)的元素;
●形式2中,子区间的元素和[searchBeg, searchEnd)的对应元素必须使二元判别式op(eleme, searchEleme)为true;
●如果没有找到符合条件的子区间,两种形式都返回end。

【例5-5】搜索容器v2中的整个元素序列是否在v1中存在,若存在,返回其首位置
#include 
#include 
#include 
using namespace std;

void main(){
     vector v1;
     cout<<"v1:";
     for(int i=0;i<5;i++){
         v1.push_back(i+5); 
//注意:v1定义时没有给定大小,因此这里不能直接使用赋值语句。
         cout< v2;
   cout<<"v2:";
   for(i=0;i<2;i++){
       v2.push_back(i+7);
       cout<::iterator ilocation;
   ilocation=search(v1.begin(),v1.end(),v2.begin(),v2.end());
   if(ilocation!=v1.end())
       cout<<"v2的元素包含在v1中,起始元素为"<<"v1["
            <
#include 
#include 
using namespace std;
void main()
{
   vector v;
   v.push_back(1);
   v.push_back(8);
   v.push_back(8);
   v.push_back(8);
   v.push_back(6);
   v.push_back(6);
   v.push_back(8);
   vector::iterator i;
   i=search_n(v.begin(),v.end(),3,8); //在v中找3个连续的元素,且它们的值均8
   
if(i!=v.end())
         cout<<"在v中找到3个连续的元素8"<
#include 
#include 
using namespace std;

void main(){
   vector v1;
   v1.push_back(-5);
   v1.push_back(1);
   v1.push_back(2);
   v1.push_back(-6);
   v1.push_back(-8);
   v1.push_back(1);
   v1.push_back(2);
   v1.push_back(-11);
   vector v2;
   v2.push_back(1);
   v2.push_back(2);
   vector::iterator i;  
   
i=find_end(v1.begin(),v1.end(),v2.begin(),v2.end());
   if(i!=v1.end())
          cout<<"v1中找到最后一个匹配v2的子序列,位置在"
                 <<"v1["<
#include 
#include 
#include 
using namespace std;

void main(){
   vector v;
   v.push_back(1);
   v.push_back(3);
   v.push_back(5);

   list l;   
   l.push_back(2);
   l.push_back(4);
   l.push_back(6);
   l.push_back(8);
   l.push_back(10);

   //在双向链表l的开始处,将向量容器v的元素全部复制过来
   copy(v.begin(),v.end(),l.begin());  

   list::iterator i;
   for(i=l.begin();i!=l.end();i++)
        cout<<*i<<' ';
   cout<
#include 
#include 
#include 
using namespace std;

int square(int x){ return x*x; }

void main(){
   vector v;
   v.push_back(5);
   v.push_back(15);
   v.push_back(25);

   cout<<"交换前向量容器的元素是:"<::iterator pos;
   for(pos=v.begin(); pos!=v.end(); ++pos)
		cout<<*pos<<"   ";
   cout< l(3);

   transform(v.begin(),v.end(),l.begin(),square); // square对诸元素平方

   list::iterator i;
   cout<<"交换后链表容器的元素(经过平方计算)是:"<
#include 
#include 
using namespace std;
void main()
{
   vector v;
   v.push_back(13);
   v.push_back(25);
   v.push_back(27);
   v.push_back(25);
   v.push_back(29);
cout<<"替换前向量容器的元素是:"<::iterator pos;
   for(pos=v.begin(); pos!=v.end(); ++pos)
		cout<<*pos<<"   ";
   cout<
#include 
#include 
using namespace std;
bool odd(int x){
    return x%2;  //不能被2整除尽时返回true
}
void main(){
   vector v;
   for(int i=1;i<10;i++)
       v.push_back(i);

   replace_if(v.begin(),v.end(),odd,100);

   vector::iterator ilocation;
   for(ilocation=v.begin();ilocation!=v.end();ilocation++)
   cout<<*ilocation<<' ';
   cout<
#include 
#include 
using namespace std;

void main(){
   vector v(10);

   fill_n(v.begin(),5,-1);  //用“-1”填充v中的前5个元素

   vector::iterator ilocation;
   for(ilocation = v.begin(); ilocation!=v.end(); ilocation++)
       cout<<*ilocation<<' ';
   cout<
#include 
#include 
using namespace std;

void main(){
   vector v(10);

  generate_n(v.begin(),5,rand); // 用rand算法生成5个随机数放入向量容器的前头

   vector::iterator ilocation;
   for(ilocation=v.begin();ilocation!=v.end();ilocation++)
   	   cout<<*ilocation<<' ';
   cout<
#include 
#include 
using namespace std;

bool even(int x)  { return x%2?0:1;}

void main(){
   vector v;
   for(int i=1;i<=10;i++)
   v.push_back(i);
   vector::iterator ilocation,result;
   cout<<"移除前:";
   for(ilocation=v.begin();ilocation!=v.end();ilocation++)
   cout<<*ilocation<<' ';
   cout<
#include 
#include 
using namespace std;

void main(){
   vector v;
   v.push_back(2);
   v.push_back(6);
   v.push_back(6);
   v.push_back(6);
   v.push_back(9);
   v.push_back(6);
   v.push_back(3);
   vector::iterator ilocation,result;
   result=unique(v.begin(),v.end());
   for(ilocation=v.begin();ilocation!=result;ilocation++)
   		cout<<*ilocation<<' ';
   cout<。常用的排序和搜索算法列在表5-3中。

表5-3  STL中常用的排序和搜索算法
序号	功能	函数名称	说       明
1	排  序	Sort	以很好的平均效率排序
		stable_sort	排序,并维持相同元素的原有顺序
		partial_sort	将序列的前一部分排好序
		partial_sort_copy	复制的同时将序列的前一部分排好序
2	第n个元素	nth_element	将第n各元素放到它的正确位置
3	二分检索
	lower_bound	找到大于等于某值的第一次出现
		upper_bound	找到大于某值的第一次出现
		equal_range	找到(在不破坏顺序的前提下)可插入给定值的最大范围
		binary_search	在有序序列中确定给定元素是否存在
4	归   并	Merge	归并两个有序序列
		inplace_merge	归并两个接续的有序序列
5	序列结构上的集合操作
	Includes	一序列为另一序列的子序列时为真
		set_union	构造两个集合的有序并集
		set_intersection	构造两个集合的有序交集
		set_difference	构造两个集合的有序差集
		set_symmetric_difference	构造两个集合的有序对称差集(并-交)
6	堆操作	make_heap	从序列构造堆/最大堆
		pop_heap	从堆中弹出元素
		push_heap	向堆中加入元素
		sort_heap	给堆排序,堆被破坏
7	最大和最小	min	两个值中较小的
		max	两个值中较大的
		min_element	序列中的最小元素
		max_element	序列中的最大元素
8	词典比较	lexicographical_compare	两个序列按字典序的第一个在前
9	排列生成器	next_permutation	按字典序的下一个排列
		prev_permutation	按字典序的前一个排列
10	数值算法	accumulate	累积和
		inner_product	内积
		partial_sum	局部求和
		adjacent_difference	临接差

下面通过举例来体会其中部分算法的作用和使用方法。
【例5-16】堆操作包括:建堆、入堆、出堆、堆排序等算法
堆(max-heap)是二叉树,根结点总是大于等于其左右孩子结点(递归定义)。在STL中,堆是最大堆(max-heap)。堆中的元素被顺序地存储在一维数组中,且第一个元素值最大。
STL提供四种堆操作算法:
1、make_heap()算法   将容器内的元素转化成heap
形式一:
    void make_heap(RandomAccessIterator beg,
RandomAccessIterator end)
形式二:
void make_heap(RandomAccessIterator beg,
RandomAccessIterator end,
BinaryPredicate op)
●  两种形式都将区间[beg,end)内的元素转化为heap;
      ● op是可有可无的二元判断式,它作为排序准则。

2、push_heap()算法    向堆中加入一个元素
形式一:
void push_heap (RandomAccessIterator beg,
RandomAccessIterator end)
形式二:
void push_heap (RandomAccessIterator beg,
RandomAccessIterator end
BinaryPredicate op)
●  两种形式都在本已经是heap的区间[beg,end)尾部加入一个新元素,然后再将整个新的区间内的元素重新转化为heap;
● op是可有可无的二元判断式,它作为排序准则;
● 调用本函数之前,必须保证原来的整个区间已经是heap。
   
3、pop_heap()算法    从堆中取出一个元素
形式一:
void pop_heap (RandomAccessIterator beg,
RandomAccessIterator end)
形式二:
void pop_heap (RandomAccessIterator beg,
RandomAccessIterator end
BinaryPredicate op)

● 一定要注意,以上两种形式都将[beg,end)内的最高元素,即第一个元素移到最后位置上,并将剩余区间[beg,end-1)内的元素组织起来,成为一个新的heap;。为了将移到最后位置上的那个已经出堆的元素物理地删除,一般在执行了pop_heap()之后,紧接着要安排执行一次pop_back()操作;
● op是可有可无的二元判断式,它作为排序准则;
● 调用本函数之前,必须保证原来的整个区间已经是heap。

4、sort_heap()算法    给堆排序,原容器不再是heap了
形式一:
void sort_heap (RandomAccessIterator beg,
RandomAccessIterator end)
形式二:
void sort_heap (RandomAccessIterator beg,
RandomAccessIterator end
BinaryPredicate op)
● 以上两种形式都将heap[beg,end)转换成一个有序序列(默认升序)。注意,此算法一旦结束,该区间就不再是一个heap了。还要注意,原区间的最后是否有因pop_heap()操作而移来的元素;
● op是可有可无的二元判断式,它作为排序准则;
● 调用本函数之前,必须保证原来的整个区间已经是heap。

介绍了有关堆操作的四个算法之后,现研读本例如下代码:

#include 
#include 
#include 
using namespace std;

void main(){
   vector v;
   v.push_back(5);
   v.push_back(6);
   v.push_back(4);
   v.push_back(8);
   v.push_back(2);
   v.push_back(3);
   v.push_back(7);
   v.push_back(1);
   v.push_back(9);
vector::iterator ilocation;

cout<<"此时向量v的元素为:\n";
for(ilocation=v.begin();ilocation!=v.end();ilocation++)
          cout<<*ilocation<<"   ";
   cout<
#include 
#include 
using namespace std;

void main()
{
   vector v;
   v.push_back(3);
   v.push_back(9);
   v.push_back(6);
   v.push_back(3);
   v.push_back(17);
   v.push_back(20);
   v.push_back(12);
   vector::iterator ilocation;

   for(ilocation=v.begin();ilocation!=v.end();ilocation++)
         cout<<*ilocation<<' ';
   cout<
#include 
#include 
using namespace std;

void main()
{
   vector v;
   v.push_back(2);
   v.push_back(8);
   v.push_back(-15);
   v.push_back(90);
   v.push_back(26);
   v.push_back(7);
   v.push_back(23);
   v.push_back(30);
   v.push_back(-27);
   v.push_back(39);
   v.push_back(55);
   vector::iterator ilocation;

   cout<<"排序前:"<。 

一、accumulate算法:    计算序列中所有元素的和。该函数重载有两个版本如下:
1、形式一
T accumulate(InputIterator beg, InputIterator end, T iniValue);
   
2、形式二
T accumulate(InputIterator beg, InputIterator end, T iniValue, BinaryFunc op);
形式一是计算iniValue和区间[beg, end)内所有元素的总和。
形式二是计算iniValue和区间[beg, end)内每一个元素进行op运算的结果。

●因此,对于如下数值序列:
a1  a2  a3  a4 …
形式一是计算:iniValue + a1 + a2 + a3 + a4 + …;
形式二是计算:iniValue  op  a1  op  a2  op  a3  op  a4  op …。

二、inner_product:    对两个序列做内积(对应元素相乘,再求和),并将内积加到一个输入的初始值上。重载版本使用用户定义的操作。
1、形式一

T inner_product (InputIterator1  beg1, InputIterator1  end1, 
InputIterator2  beg2, T iniValue);

2、形式二

T inner_product (InputIterator1  beg1, InputIterator1  end1, 
InputIterator2  beg2, T iniValue
BinaryFunc op1,BinaryFunc op2);

形式一是计算并返回[beg1, end1)区间和“以beg2为起始的区间”的对应元素组(再加上iniValue)的内积。具体地说,也就是针对“两区间内的每一组对应元素”调用以下表达式:
iniValue = iniValue + elem1  *  elem2

形式二将[beg1, end1)区间和“以beg2为起始的区间”的对应元素组进行op2运算,然后再和iniValue进行op1运算,并将结果返回。具体地说,也就是针对“两区间内的每一组对应元素”调用以下表达式:
iniValue = op1(iniValue, op2( elem1, elem2))

●因此,对于如下数值序列:
a1  a2  a3  …
        b1  b2  b3  …
形式一是计算并返回:iniValue + (a1 * b1) + (a2 * b2) + (a3 * b3)  + …;
形式二是计算并返回:iniValue  op1  (a1  op2  b1)   op1  (a2  op2  b2) 
 op1  (a3  op2  b3)  op1  …。

三、partial_sum:    对序列中部分元素的值进行累加,并将结果保存在另一个序列中。
1、形式一
OutputIterator
partial_sum (InputIterator sourceBeg,
InputIterator sourceEed,
                OutputIterator destBeg );

2、形式二
OutputIterator
partial_sum (InputIterator sourceBeg,
InputIterator sourceEed,
                OutputIterator destBeg , BinaryFunc op);
形式一是计算区间[sourceBeg, sourceEed)中每个元素的部分和,然后将结果写入以destBeg为起点的目标区间。
形式二是将区间[sourceBeg, sourceEed)中每个元素和其先前所有元素进行op运算,并将结果写入以destBeg为起点的目标区间。
●因此,对于如下数值序列:
a1  a2  a3  …
形式一是计算:a1,  a1  +  a2,  a1  +  a2  +  a3,  …;
形式二是计算:a1,  a1  op  a2,  a1  op  a2  op  a3, …。

四、adjacent_difference:   计算序列中相邻元素的差,并将结果保存在另一个序列中。
1、形式一
OutputIterator
partial_sum (InputIterator sourceBeg,
InputIterator sourceEed,
                OutputIterator destBeg );
2、形式二
OutputIterator
partial_sum (InputIterator sourceBeg,
InputIterator sourceEed,
                OutputIterator destBeg , BinaryFunc op);

形式一是计算区间[sourceBeg, sourceEed)中每个元素和其紧邻前驱元素的差,并将结果写入以destBeg为起点的目标区间。
形式二是针对区间[sourceBeg, sourceEed)中每个元素和其先前所有元素调用op操作,并将结果写入以destBeg为起点的目标区间。
●因此,对于如下数值序列:
a1  a2  a3  …
形式一是计算:a1,  a2  –  a1,  a3  –  a2,  a4  –  a3  …;
形式二是计算:a1,  a2  op  a1,  a3  op  a2,  a4  op  a3  …。

【例5-19】STL 数值算法举例
#include 
#include 
#include 
#include 
using namespace std;

void main()
{
	int iarray[]={1,2,3,4,5};
vectorivector(iarray,
iarray+sizeof(iarray)/sizeof(int));//此行求数组元素个数

cout<(cout,"  "));
cout<(cout,"  "));
cout<  	   如果第一个容器大于第二个容器,返回true,否则返回false
operator>=  	   如果第一个容器大于或等于第二个容器,返回true,否则返回false
operator==  	   如果第一个容器等于第二个容器,返回true,否则返回false
operator!=  	   如果第一个容器不等于第二个容器,返回true,否则返回false
swap   		   交换两个容器的元素
§2  顺序容器和关联容器共有函数
begin 	 返回iterator或const_iterator,引用容器第一个元素位置
end   	 返回iterator或const_iterator,引用容器最后一个元素后面一个位置
rbegin  返回reverse_iterator或const_reverse_iterator,引用容器最后一个元素
	rend    返回reverse_iterator或const_reverse_iterator,引用容器首个元素前面一位
erase   从容器中清除一个或几个元素
clear    清除容器中所有元素
§3  容器比较 
vector(连续的空间存储,可以使用[]操作符)快速的访问随机的元素,快速的在末尾插入元素,但是在序列中间岁间的插入,删除元素要慢,而且如果一开始分配的空间不够的话,有一个重新分配更大空间,然后拷贝的性能开销。
deque(小片的连续,小片间用链表相连,实际上内部有一个map的指针,因为知道类型,所以还是可以使用[],只是速度没有vector快)快速的访问随机的元素,快速的在开始和末尾插入元素,随机的插入,删除元素要慢,空间的重新分配要比vector快,重新分配空间后,原有的元素不需要拷贝。对deque的排序操作,可将deque先复制到vector,排序后在复制回deque。
list(每个元素间用链表相连)访问随机元素不如vector快,随机的插入元素比vector
快,对每个元素分配空间,所以不存在空间不够,重新分配的情况。
set 内部元素唯一,用一棵平衡树结构来存储,因此遍历的时候就排序了,查找也
比较快。
map 一对一的映射的结合,key不能重复。
§4  vector容器常用成员函数
 (1)构造函数
 vector();    创建一个空vector
 vector(int nSize);    创建一个vector, 元素个数为nSize
 vector(int nSize, const T& t);    创建一个vector,元素个数为nSize, 且值均为t
 vector(const vector&);    拷贝构造函数

(2)增加函数
 void push_back(const T& x);    向量尾部增加一个元素x
 iterator insert(iterator it, const T& x);    向量中某一元素前增加一个元素x
 void insert(iterator it, int n, const T& x);    向量中某一元素前增加n个相同元素x
 void insert(iterator it,const_iterator first, const_iterator last);    向量中某一元素前插入另一个相同类型向量的[first,last)间的数据

(3)删除函数
 iterator erase(iterator it);    删除向量中某一个元素
 iterator erase(iterator first, iterator last);    删除向量中[first,last)中元素
 void pop_back();    删除向量中最后一个元素
 void clear();	    删除向量中所有元素

(4)遍历函数
 reference at(int pos);    返回pos位置元素的引用
 reference front()	;    返回首元素的引用
 reference back();    返回尾元素的引用
 iterator begin();    返回向量头指针,指向第一个元素
 iterator end();    返回向量尾指针,不包括最后一个元素,在其下面
 reverse_iterator rbegin();    反向迭代器,功能等同iterator end()
 reverse_iterator rend();    反向迭代器,功能等同iterator begin()

(5)判断函数
 bool empty() const;    向量是否为空?若true,则向量中无元素。

(6)大小函数
 int size() const;    返回向量中元素的个数
 int capacity() const;    返回当前向量所能容纳的最大元素值
 int max_size() const;    返回最大可允许的vector元素数量值

(7)其它函数
 void swap(vector&);    交换两个同类型向量的数据
 void assign(int n, const T& x);    向量中第n个元素设置成元素x
 void assign(const_iterator first, const_iterator last);    向量中[first,last]元素设置成当前向量元素
                                                                                
§5  deque容器常用成员函数
 (1)构造函数
 deque();    创建一个空deque
 deque(int nSize);    创建一个deque, 元素个数为nSize
 deque(int nSize, const T& t);    创建一个deque,元素个数为nSize, 且值均为t
 deque (const deque &);    拷贝构造函数

(2)增加函数
 void push_front(const T& x);    双端队列头部增加一个元素x
 void push_back(const T& x);    双端队列尾部增加一个元素x
 iterator insert(iterator it, const T& x);    双端队列中某一元素前增加一个元素x
 void insert(iterator it, int n, const T& x);    双端队列中某一元素前增加n个相同元素x
 void insert(iterator it,const_iterator first, const_iterator last);    双端队列中某一元素前插入另一个相同类型向量的[first,last)间的数据

(3)删除函数
 iterator erase(iterator it);	;删除双端队列中某一个元素
 iterator erase(iterator first, iterator last)	;删除双端队列中[first,last)中元素
 void pop_front();		;删除双端队列中最后一个元素
 void pop_back();		;删除双端队列中最后一个元素
 void clear();		;删除双端队列中所有元素

(4)遍历函数
 reference at(int pos)	;返回pos位置元素的引用
 reference front()		;返回首元素的引用
 reference back()		;返回尾元素的引用
 iterator begin()		;返回向量头指针,指向第一个元素
 iterator end()		;返回向量尾指针,不包括最后一个元素,在其下面
 reverse_iterator rbegin()	;反向迭代器,功能等同iterator end()
 reverse_iterator rend()	;反向迭代器,功能等同iterator begin()

(5)判断函数
 bool empty() const		;向量是否为空?若true,则向量中无元素。

(6)大小函数
 int size() const		;返回向量中元素的个数
 int max_size() const	;返回最大可允许的双端队列元素数量值

(7)其它函数
 void swap(vector&)	;交换两个同类型向量的数据
 void assign(int n, const T& x);向量中第n个元素设置成元素x
 void assign(const_iterator first, const_iterator last);向量中[first,last]元素设置成当前向量元素
                                                                                  
说明:deque可以通过push_front直接在容器头增加元素,通过pop_front直接删除容器头元素,这一点是vector元素不具备的。

§6  list容器常用成员函数
 (1)构造函数
 list c		;创建一个空的list
 list c1(c2)		;拷贝另一个同类型元素的list
 list c(n)		;创建n个元素的list, 每个元素值由缺省构造函数确定
 list c(n,elem)	;创建n个元素的list,每个元素值为elem
 list c(begin,end)	;由迭代器创建list,迭代区间为[begin,end]

(2)大小、判断空函数
 int size() const		;返回容器元素个数
 bool empty() const		;判断容器是否空,若返回true,表明容器已空

(3)增加、删除函数:
 void push_back(const T& x)	;list容器尾元素后增加一个元素x
 void push_front(const T& x)	;list容器首元素前增加一个元素x
 void pop_back();		;删除容器尾元素,当且仅当容器不为空
 void pop_front();		;删除容器首元素,当且仅当容器不为空
 void remove(const T& x);	;删除容器中所有元素值等于x的元素
 void clear();		;删除容器中所有元素
 iterator insert(iterator it, const T& x = T());在迭带器指针it前插入元素x, 返回x迭带器指针
void insert(iterator it, size_type n, const T& x);在迭带器指针it前插入n个相同元素x
void insert(iterator it, const_iterator first, const_iterator last);把[first, last)间的元素插入迭  带指针it前
iterator erase(iterator it);	  删除迭带器指针it对应的元素
iterator erase(iterator first, iterator last);删除迭带器指针[first, last)间的元素

(4)遍历函数
iterator begin();		返回首元素的迭带器指针
iterator end();		 返回尾元素后的迭带器指针,而不是尾元素的迭带器指针
reverse_iterator rbegin();	 返回尾元素的逆向迭带器指针,用于逆向遍历容器
reverse_iterator rend();	 返回首元素前的逆向迭带器指针,用于逆向遍历容器
reference front();		 返回首元素的引用
reference back();    返回尾元素的引用

(5)操作函数
void sort();    容器内所有元素排序,默认是升序
template  void sort(Pred pr);   容器内所有元素根据预判定函数pr排序
void swap(list& str);    两list容器交换功能
void unique();    容器内相邻元素若有重复的,则仅保留一个
void splice(iterator it, list& x);	  队列合并函数,队列x所有元素插入迭代指针it前,x变成空队列
void splice(iterator it, list& x, iterator first);    队列x中移走[first,end)间元素插入迭代指针it前
void splice(iterator it, list& x, iterator first, iterator last);     x中移走[first,last)间元素插入迭代指针it前
void reverse();		 反转容器中元素顺序

§7  队列和堆栈常用成员函数

(1)构造函数
queue(class T, class Container=deque);    创建元素类型为T的空队列,默认容器是deque
stack(class T, class Container=deque);    创建元素类型为T的空堆栈,默认容器是deque

(2)操作函数
	bool empty();	如果队列(堆栈)为空返回true, 否则返回false
int size();  	返回队列(堆栈)中元素数量
void push(const T& t);	把t元素压入队尾(栈顶)
void pop();		当队列(栈)非空情况下,删除队头(栈顶)元素  队列独有函数:
T& front();		当队列非空情况下,返回队头元素引用
T& back();		当队列非空情况下,返回队尾元素引用堆栈独有函数:
T& top();		当栈非空情况下,返回栈顶元素的应用

§8  优先队列常用成员函数
 	
(1)构造函数
priority_queue(const Pred& pr = Pred(),const allocator_type& al = allocator_type());
创建元素类型为T的空优先队列,Pred是二元比较函数,默认是less
priority_queue(const value_type *first, const value_type *last,const Pred& pr = Pred(), const allocator_type& al = allocator_type());    以迭代器[first,last)指向元素创建元素类型为T的优先队列,Pred是二元比较函数,默认是less。

(2)操作函数
	队列和堆栈共有函数:
bool empty();	如果优先队列为空返回true, 否则返回false
int size();  	返回优先队列中元素数量
void push(const T& t);	把t元素压入优先队列
void pop();		当优先队列非空情况下,删除优先级最高元素
T& top();		当优先队列非空情况下,返回优先级最高元素的引用
 
§9  集合常用成员函数
set 、multiset都是集合类,差别在于set中不允许有重复元素,multiset中允许有重复元素。

(1)构造函数
set(const Pred& comp = Pred(), const A& al = A());    创建空集合
set(const set& x);    拷贝构造函数
set(const value_type *first, const value_type *last,const Pred& comp = Pred(), const A& al = A());    拷贝[first,last)之间元素构成新集合
multiset(const Pred& comp = Pred(), const A& al = A());    创建空集合
multiset(const multiset& x);    拷贝构造函数
multiset(const value_type *first, const value_type *last,const Pred& comp = Pred(), const A& al = A());    拷贝[first,last)之间元素构成新集合

(2)大小、判断空函数
int size() const;    返回容器元素个数
bool empty() const;    判断容器是否空,若返回true,表明容器已空

(3)增加、删除函数
pair insert(const value_type& x);    插入元素x
iterator insert(iterator it, const value_type& x);    在迭代指针it处,插入元素x
void insert(const value_type *first, const value_type *last);    插入[first, last)间元素
iterator erase(iterator it);	   删除迭代指针it处元素
iterator erase(iterator first, iterator last);    删除[first, last)迭代指针间元素
size_type erase(const Key& key);    删除元素值等于key的元素

(4)遍历函数
iterator begin();		返回首元素的迭带器指针
iterator end();		返回尾元素后的迭带器指针,而不是尾元素的迭带器指针
reverse_iterator rbegin();    返回尾元素的逆向迭带器指针,用于逆向遍历容器
reverse_iterator rend();    返回首元素前的逆向迭带器指针,用于逆向遍历容器

(5)操作函数
const_iterator lower_bound(const Key& key);    返回容器元素等于key迭代指针,否则返回end()
const_iterator upper_bound(const Key& key);
int count(const Key& key) const;    返回容器中元素值等于key的元素个数
pair equal_range(const Key& key) const;    返回容器中元素值等于key的迭代指针[first, last)
const_iterator find(const Key& key) const;    查找功能,返回元素值等于key迭代器指针
void swap(set& s);    交换单集合元素
void swap(multiset& s);    交换多集合元素

§10  映射常用成员函数
常用的映射类是map, multimap。在前述的各个容器中,仅保存着一样东西,但是在映射中将会得到两样东西:关键字以及作为对关键字进行查询得到的结果值,即一对值。map单映射中Key与Value是一对一的关系,multimap多映射中Key与Value可以是一对多的关系。

(1)构造函数
map(const Pred& comp = Pred(), const A& al = A());    创建空映射
map(const map& x);    拷贝构造函数
map(const value_type *first, const value_type *last,const Pred& comp = Pred(), const A& al = A());    拷贝[first,last)之间元素构成新映射
multimap(const Pred& comp = Pred(), const A& al = A());    创建空映射
multimap(const multimap& x);	拷贝构造函数
multimap(const value_type *first, const value_type *last,  const Pred& comp = Pred(), const A& al = A());    拷贝[first,last)之间元素构成新映射 

(2)大小、判断空函数
int size() const;    返回容器元素个数
bool empty() const;    判断容器是否空,若返回true,表明容器已空

(3)增加、删除函数
iterator insert(const value_type& x);	插入元素x
iterator insert(iterator it, const value_type& x);    在迭代指针it处插入元素x
void insert(const value_type *first, const value_type *last);    插入[first,last)间元素
iterator erase(iterator it);    删除迭代指针it处元素
iterator erase(iterator first, iterator last);    删除[first, last)迭代指针间元素
size_type erase(const Key& key);    删除键值等于key的元素 

(4)遍历函数
iterator begin();    返回首元素的迭带器指针
iterator end();     返回尾元素后的迭带器指针,而不是尾元素的迭带器指针
reverse_iterator rbegin();	   返回尾元素的逆向迭带器指针,用于逆向遍历容器
reverse_iterator rend();	   返回首元素前的逆向迭带器指针,用于逆向遍历容器

(5)操作函数
const_iterator lower_bound(const Key& key);    返回键值等于key迭代指针,否则返回end()
const_iterator upper_bound(const Key& key);
int count(const Key& key) const;    返回容器中键值等于key的元素个数
pair equal_range(const Key& key) const;    返回容器中键值等于key的迭代指针[first, last)
const_iterator find(const Key& key) const;  查找功能,返回键值等于key迭代器指针
void swap(map& s);	   交换单映射元素
void swap(multimap& s);	   交换多映射元素

(6)特殊函数
reference operator[](const Key& k);    仅用在单映射map类中,可以以数组的形式给映射添加键---值对,并可返回值的引用。

 

你可能感兴趣的:(C++)