C++标准库与STL的关系
1.STL入门
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
在C++标准中,STL被组织为下面的13个头文件:、
例1
#include //包含头文件
#include
using namespace std;
int main()
{
vector a; //定义数据变量
vector::const_iterator i; //定义变量
a.push_back(1); //调用STL中函数
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);
for(i=a.begin();i!=a.end();i++)//循环输出
{
cout<<(*i)<
结果:
上述代码中,使用了push_back()、begin()和end()函数,而这些函数在程序中并没有被定义过,却可以使用,这是因为这些函数已经被头文件vector.h所包含,如果strcpy()被string.h包含一样。
例2.
#include
#include
#include
#include
using namespace std;
template
struct Print
{
void operator()(T& x) const//const说明此成员函数不修改类的数据成员
{
if(0==x%2)
{
cout< vcInts;
for(int i=0;i<10;i++)
{
vcInts.push_back(i);
}
vector::iterator iterBegin,iterEnd;//定义两个迭代器,分别用来撒向容器的开始和结尾
iterBegin = vcInts.begin();
iterEnd = vcInts.end();
cout<<"输出所有元素: "<());//通过算法for_each和函数对象Print输出容器中的元素
cout<
结果
2.算法
STL中的算法部分主要由头文件
#include
#include
#include
#include
using namespace std;
class myclass
{
public:
myclass(int a,int b):first(a),second(b){}
int first;
int second;
bool operator < (const myclass &m)const //重载运算符<
{
return first < m.first;
}
};
bool less_second(const myclass &m1,const myclass &m2) //根据第2个元素比大小
{
return m1.second vct;
for(i=0;i<10;i++)
{
myclass my(10-i,i*3);
vct.push_back(my);
}
for(i=0;i
结果
3.容器
容器部分主要由头文件、
3.1容器——向量(vector)
例1
#include
#include
using namespace std;
char* szHW = "Hello World";
int main(int argc,char* argv[])
{
vector vct;//声明一个字符向量 vector
vector :: iterator vi;//为字符数组字义一个游标iterator
char* cptr = szHW;
while(*cptr!='\0')//初始化字符向量,对整个字符串进行循环,用来把数据填放到字符向量中,直到遇到'\0'时结束
{vct.push_back(*cptr);cptr++;}//push_back将数据放在向量的尾部
for(vi=vct.begin();vi!=vct.end();vi++)//将向量中的字符一个个地显示在控制台,这是STL循环的规范化开始,通常是"!=",而不是"<",因为"<"在一些容器中没有定义
cout<<*vi;//使用运算符"*"将数据从游标指针中提取出来
cout<
上例中使用了向量
例2.也可以像数组一样访问vector元素,如下:
#include
#include
using namespace std;
int main()
{
vector a;
for(int i=0;i<10;i++)//这里的i是int型数据,不是迭代器
a.push_back(i*i);
for(int i=0;i
例3 在容器中查找特定值的元素,并显示下标位置
#include
#include
#include
using namespace std;
int main()
{
vector a(10);
vector::iterator i;
a[5]=100;//把a[5]设为100
for(i=a.begin();i!=a.end();i++)
cout<<*i<<" ";
cout<::iterator intIter=find(a.begin(),a.end(),100);//查找值为100的迭代器
if(intIter!=a.end())//end 返回的 不是最后一个位置的元素的指针。是最后一个元素指针+1
{
cout<<"找到:"<<*intIter<
vector中定义了以下4种构造函数
1)默认构造函数
构造一个初始长度为0的空向量,其调用格式如:
vector
2)带有单位整形参数的构造函数
此参数描述了向量的初始大小,该构造函数还有一个可选的参数,这是一个类型为T的实例,描述了各个向量中各成员的初始值,其调用如(此时的T为int):
vector
3)带有两个常量参数的构造函数
产生初始值为一个区间的向量。区间由一个半开区间[first,last)来指定,其调用格式如下:
vector
注意:stl体系中,所有用到一对迭代器的,都是左闭右开,[ begin(), end() )。end 返回的不是最后一个位置的元素的指针,是最后一个元素指针+1。
4)复制构造函数
构造一个新的向量,作为已存在的向量的完全复制,其调用如下:
vector
此外,在实际程序中使用较多的是向量类的成员函数,其常用的成员函数如下。
begin()、end()、push_back()、insert()、assign()、front()、back()、erase()、empty()、at()、size()。
3.2容器——列表
列表也是容器类的一种,其所控制的长度为N的序列是以一个有着N个节点的双向链表来存储的,支持双向迭代器,其预编译头文件为#include
模板list的另一个特点是在异常处理方面,对任何容器来说,容器成员函数在执行中抛出的异常,使容器本身处于一种一致状态,可以被销毁,并且容器没有对所分配的存储空间失去控制。但对大部分操作尤其是那些能够影响多个元素的操作,当抛出异常时,并没有制定容器的精确状态,但list保证对于大部分成员函数抛出异常时,容器能够恢复到操作前的状态。列表类的定义如下:
list
成员函数如下:resize() clear() front() back() push_back() push_front() pop_back() pop_front() assign() insert() erase() splice() remove() remove_if() unique() sort() merge() reverse()。
#include
#include
int main()
{
using namespace std;
list c1;
list:: iterator c1_iter;
c1.push_back(20);
c1.push_back(10);
c1.push_back(30);
cout<<"Before sorting c1 = ";
for(c1_iter = c1.begin();c1_iter!=c1.end();c1_iter++)//输出列表内容
cout<<" "<<*c1_iter;
cout<());//调用降序排序函数
cout<<"After sorting with 'greater than' operation, c1 = ";
for(c1_iter = c1.begin();c1_iter!=c1.end();c1_iter++)//输出降序排列后内容
cout<<" "<<*c1_iter;
cout<
结果
3.3容器——集合
集合(set)也是容器的一种,它的特点在集合中的元素值是唯一的。在集合中,所有成员都是排列好的。如果先后往一个集合中插入:4,3,2,5,则输出该集合时为:2,3,4,5。
#include
#include
#include
using namespace std;
int main()
{
set strset;
set ::iterator si;
strset.insert("Apple");
strset.insert("Bnana");
strset.insert("Orange");
strset.insert("Plate");
strset.insert("Grapes");
strset.insert("Grapes");
for(si=strset.begin();si!=strset.end();si++)
cout<<*si<<" ";
cout<
上例中,Grapes虽然插入了两次,但同样的元素只出现一次。
3.4容器——双端队列
双端队列是一个queue容器类(即队列容器),其定义在头文件deque中(即double queue)。在使用该容器时,需在头文件中加上如下语句:#include
与vector相同点:支持随机访问和快速插入删除,它在窗口中某一位置上的操作所花费的是线性时间。
与vector不同点:deque还支持从开始端插入数据,因为其包含在开始端插入数据的函数push_front()。此外deque也不支持与vector类似的capacity(),reserve()类似的操作。例1:
#include
#include
using namespace std;
typedef deque INTDEQUE;
void put_deque(INTDEQUE deque,char* name)//从前向后显示deque的全部元素
{
INTDEQUE::iterator pdeque;
cout <<"The contents of "<
例2
#include
#include
#include
using namespace std;
int main()
{
deque a;
string word;
for(int i=0;i<5;i++)
{
cin>>word;
a.push_back(word);
}
a.pop_front();//从前面删除一个元素
a.pop_back();//从后面删除一个元素
for(int i=0;i
3.5容器——栈
容器栈(stack)是一种特殊的容器,其特征是后进先出。支持以下5种操作:
empty():如果栈空,返回true,否则返回false。
size():返回栈中元素的个数。
pop():删除,但不返回栈顶元素。
top():返回,但不删除栈顶元素。
push():放入新的栈顶元素。
#include
#include
using namespace std;
int main()
{
const int ia_size = 10;
int ia[ia_size]={0,1,2,3,4,5,6,7,8,9};
int ix = 0;
stack intStack;
for(;ix
3.6容器——映射和多重映射
映射和多重映射用于对数据进行快速和高效的检索。同样地,在程序中使用映射和多重映射容器需添加如下头文件:#include
映射map支持下标运算符operator[],可以用访问普通数据的方式访问map,或下标为map的键。而在mutimap中一个键可以对应多个不同的值。
#include
4.迭代器
迭代器实际上是一种泛化指代指针,如果一个迭代器指向容器中的某个成员,那么迭代器将可以通过自增 自减来遍历容器中的所有成员。迭代器是联系容器和算法的媒介,是算法操作容器的接口。
STL中的迭代器主要是由头文件
例如:下面程序实现使用输入/输出迭代器完成了将一个文件里的内容输出到屏幕的功能。
#include
#include
#include
#include
#include
using namespace std;
int main()
{
vector v1;
ifstream file("test.txt");
if(file.fail())
{cout<<"打开文件失败,请确定要打开的文件存在"<(file),istream_iterator(),inserter(v1,v1.begin()));//如果没有#include这里会报错
copy(v1.begin(),v1.end(),ostream_iterator(cout," "));
cout<
上述代码中,用到了输入迭代器istream_iterator,输出迭代器ostream_iterator。程序完成了将一个文件输出到屏幕的功能,先将文件读入,然后通过迭代器把文件内容复制到类型为字符串的向量容器内,最后输出迭代器输出。inserter是一个输入迭代器函数(迭代器适配器),其使用方法是:
inserter(container ,pos);
综合范例:下面程序救出范围在2~N中的所有素数,其中N在程序运行时由键盘输入,实现代码如下。
#include
#include//IO控制流头文件
#include
using namespace std;
int main()
{
vector A(10);
int n;
int primecount = 0,i,j;
cout<<"Enter a value > 2 as upper limit: ";
cin>>n;
A[primecount++]=2;
for(i=3;ii/2)//是素数
A[primecount++] = i;//写入向量
}
for(i=0;i