基础备忘:STL基本范例

C++标准库与STL的关系
1.STL入门
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、
<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
例1
上述代码中,使用了push_back()、begin()和end()函数,而这些函数在程序中并没有被定义过,却可以使用,这是因为这些函数已经被头文件vector.h所包含,如果strcpy()被string.h包含一样。
例2.
上述代码重载了括号运算符"()",所以可以当做一个函数对象使用。两个迭代器iterBegin和iterEnd分别指向容器的开始和结尾。可以利用这两个迭代器遍历整个容器。最后调用了for_each算法,并结合使用函数对象Print。for_each的行为类似for循环。2.算法
STL中的算法部分主要由头文件<algorithm>、<numeric>和<functional>组成。例:
3.容器
容器部分主要由头文件<vector>、<list>、<deque>、<set>、<map>、<stack>和<queue>组成。
3.1容器——向量(vector)
例1
上例中使用了向量<vector>容器类。STL容器中大约有一半是基于向量的。事实上,vector是一种动态数组,是基本数组的类模板。其内部定义了很多基本操作。既然这是一个类,那么它就会有自己的构造函数。预编译头文件为#include<vector>。
例2.也可以像数组一样访问vector元素,如下:
例3 在容器中查找特定值的元素,并显示下标位置
vector中定义了以下4种构造函数
1)默认构造函数
构造一个初始长度为0的空向量,其调用格式如:
vector<int> v1;
2)带有单位整形参数的构造函数
此参数描述了向量的初始大小,该构造函数还有一个可选的参数,这是一个类型为T的实例,描述了各个向量中各成员的初始值,其调用如(此时的T为int):
vector<int> v2(init_size,0);//要事先定义init_size,表示向量的初始大小,其成员都被初始化为0
3)带有两个常量参数的构造函数
产生初始值为一个区间的向量。区间由一个半开区间[first,last)来指定,其调用格式如下:
vector<int> v3(firs,last);
注意:stl体系中,所有用到一对迭代器的,都是左闭右开,[ begin(), end() )。end 返回的不是最后一个位置的元素的指针,是最后一个元素指针+1。
4)复制构造函数
构造一个新的向量,作为已存在的向量的完全复制,其调用如下:
vector<int> v4(v3);
此外,在实际程序中使用较多的是向量类的成员函数,其常用的成员函数如下。
begin()、end()、push_back()、insert()、assign()、front()、back()、erase()、empty()、at()、size()。
3.2容器——列表
列表也是容器类的一种,其所控制的长度为N的序列是以一个有着N个节点的双向链表来存储的,支持双向迭代器,其预编译头文件为#include<list>
模板list的另一个特点是在异常处理方面,对任何容器来说,容器成员函数在执行中抛出的异常,使容器本身处于一种一致状态,可以被销毁,并且容器没有对所分配的存储空间失去控制。但对大部分操作尤其是那些能够影响多个元素的操作,当抛出异常时,并没有制定容器的精确状态,但list保证对于大部分成员函数抛出异常时,容器能够恢复到操作前的状态。列表类的定义如下:
list<T,allocator<T> > ls;//使用默认模板参数,可以省略第2个参数。
成员函数如下:resize() clear() front() back() push_back() push_front() pop_back() pop_front() assign() insert() erase() splice() remove() remove_if() unique() sort() merge() reverse()。
3.3容器——集合
集合(set)也是容器的一种,它的特点在集合中的元素值是唯一的。在集合中,所有成员都是排列好的。如果先后往一个集合中插入:4,3,2,5,则输出该集合时为:2,3,4,5。
上例中,Grapes虽然插入了两次,但同样的元素只出现一次。
3.4容器——双端队列
双端队列是一个queue容器类(即队列容器),其定义在头文件deque中(即double queue)。在使用该容器时,需在头文件中加上如下语句:#include<deque>
与vector相同点:支持随机访问和快速插入删除,它在窗口中某一位置上的操作所花费的是线性时间。
与vector不同点:deque还支持从开始端插入数据,因为其包含在开始端插入数据的函数push_front()。此外deque也不支持与vector类似的capacity(),reserve()类似的操作。例1:
例2
3.5容器——栈
容器栈(stack)是一种特殊的容器,其特征是后进先出。支持以下5种操作:
empty():如果栈空,返回true,否则返回false。
size():返回栈中元素的个数。
pop():删除,但不返回栈顶元素。
top():返回,但不删除栈顶元素。
push():放入新的栈顶元素。
3.6容器——映射和多重映射
映射和多重映射用于对数据进行快速和高效的检索。同样地,在程序中使用映射和多重映射容器需添加如下头文件:#include<map>
映射map支持下标运算符operator[],可以用访问普通数据的方式访问map,或下标为map的键。而在mutimap中一个键可以对应多个不同的值。
4.迭代器
迭代器实际上是一种泛化指代指针,如果一个迭代器指向容器中的某个成员,那么迭代器将可以通过自增 自减来遍历容器中的所有成员。迭代器是联系容器和算法的媒介,是算法操作容器的接口。
STL中的迭代器主要是由头文件<utility>、<iterator>、<memory>组成。
<utility>包括了贯穿使用在STL中的几个模板声明。
<iterator>头文件中提供了迭代器使用的许多方法。
<memory>头文件中的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。
例如:下面程序实现使用输入/输出迭代器完成了将一个文件里的内容输出到屏幕的功能。
上述代码中,用到了输入迭代器istream_iterator,输出迭代器ostream_iterator。程序完成了将一个文件输出到屏幕的功能,先将文件读入,然后通过迭代器把文件内容复制到类型为字符串的向量容器内,最后输出迭代器输出。inserter是一个输入迭代器函数(迭代器适配器),其使用方法是:
inserter(container ,pos);
综合范例:下面程序救出范围在2~N中的所有素数,其中N在程序运行时由键盘输入,实现代码如下。
上述代码中,使用了向量容器,用于存储素数。该程序采用循环取余的方法求出范围在2~N中的所有素数。
- 1楼BYD123昨天 15:30
- 不错。
- Re: generalhking昨天 16:37
- 回复BYD123n谢谢,呵呵