C++——标准模板库
1、泛型程序设计:将程序尽可能写的通用,将算法从特定的数据结构中抽象出来,成为通用的;C++模板为泛型程序设计奠定了关键的基础;STL是泛型程序设计的一个范例:容器container、迭代器iterator、算法algorithms和函数对象function object。
2、命名空间namespace:一个命名空间将不同的标识符集合在一个命名作用域(named scope)中,是为了解决命名冲突。没有声明命名空间的标识符都处在无名的命名空间中。
例如,声明一个命名空间NS:
namspace NS {
class File;
void Fun ();
}
则引用标识符的方式如下,
NS:: File obj;
NS:: Fun ();
可以利用using namespace std;指定在命名空间std中所有标识符都可以直接饮用,using NS::file;在当前作用域中就可以直接饮用file。
在新的C++标准程序库中,所有标识符都声明在命名空间std中,头文件都不使用扩展名。
3、容器:容器类是容纳、包含一组元素或元素集合的对象。异类容器类与同类容器类。还可以分为顺序容器与关联容器。七种基本容器:向量(vector)、双端队列(deque)、列表(list)、集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)
容器的接口:外界可以使用的功能。包括方法函数和运算符。
通用运算符:==,!=,>,>=,<,<=,=
迭代方法begin(),end(),rbegin(),rend();访问方法size(),max_size(),swap(),empty()
顺序容器:接口:插入方法 push_front(), push_back(), insert(), 运算符"="。
删除方法 pop(), erase(),clear()
迭代访问方法 使用迭代器
其他顺序容器访问方法(不修改的访问方法) front(),back(),下标运算符[]。
顺序容器向量:向量属于顺序容器,用于容纳不定长的线性序列,提供对序列的快速随机访问,就是直接访问。向量是动态结构,它的大小不固定,可以在程序运行时增加或者减少。
例子:求反问2~N中的质数,N在程序运行时由键盘输入。
#include <iostream>
#include <iomanip>
#include <vector> //包含向量容器头文件
using namespace std ;
int main()
{
vector<int> A(10); // 用来存放质数的向量,初始状态有10个元素。
int n; //质数范围的上限,运行时输入
int primecount = 0, i, j;
cout << "Enter a value >= 2 as upper limit for prime numbers: ";
cin >> n;
A[primecount++] = 2; // 2是一个质数
for(i = 3; i < n; i++)
{
if (primecount == A.size()) // 如果质数表已满,则再申请10个元素的空间
A.resize(primecount + 10);
if (i % 2 == 0) //大于2的偶数不是质数,因此略过本次循环的后继部分
continue;
// 检查3,5,7,...,i/2是否i的因子
j = 3;
while (j <= i/2 && i % j != 0)
j += 2;
if (j > i/2) // 若上述参数均不为i的因子,则i为质数
A[primecount++] = i;
}
for (i = 0; i < primecount; i++) //输出质数
{
cout << setw(5) << A[i];
if ((i+1) % 10 == 0) //每输出10个数换行一次
cout << endl;
}
cout << endl;
}
4、适配器:适配器是一种接口类,为已有的类提供新的接口,目的是简化、约束,使之安全、隐藏或者改变被修改类提供的服务的集合。主要有三种适配器类型:容器适配器(用来扩展7中基本容器),迭代器适配器和函数对象适配器。
5、迭代器:是面向对象版本的指针,提供了访问容器、序列中每个元素的方法
输入迭代器
可以用来从序列中读取数据
输出迭代器
允许向序列中写入数据
前向迭代器
既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
双向迭代器
与前向迭代器相似,但是在两个方向上都可以对数据遍历
随机访问迭代器
也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转。
6、算法:标准模板库中包括了70多个算法,其中包括了查找算法、排序算法、消除算法、计数算法、比较算法、变换算法、置换算法和容器管理等等
算法是一种函数模板,可以分为
不可变序列算法(non-mutating algorithms),不直接修改所操作的容器内容的算法
可变序列算法(mutating algorithms),可以修改它们所操作的容器的元素。
排序相关算法和数值算法
例6-1,应用不可变序列算法对数据序列进行分析
例6-2,以可变序列算法对数据序列进行复制,生成,删除,替换,倒序,旋转等可变性操作。
例6-3,应用排序相关算法对序列进行各项操作
例6-4,应用数值算法对数据序列进行操作
//6-1.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={0,1,2,3,4,5,6,6,6,7,8};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
int iarray1[]={6,6};
vector<int> ivector1(iarray1,iarray1+sizeof(iarray1)/sizeof(int));
int iarray2[]={5,6};
vector<int> ivector2(iarray2,iarray2+sizeof(iarray2)/sizeof(int));
int iarray3[]={0,1,2,3,4,5,7,7,7,9,7};
vector<int> ivector3(iarray3,iarray3+sizeof(iarray3)/sizeof(int));
//找出ivector之中相邻元素值相等的第一个元素
cout<<*adjacent_find(ivector.begin(),ivector.end())<<endl;
//找出ivector之中元素值为6的元素个数
cout<<count(ivector.begin(),ivector.end(),6)<<endl;
//找出ivector之中小于7的元素个数
cout<<count_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),7))<<endl;
//找出ivector之中元素值为4的第一个元素所在位置的元素
cout<<*find(ivector.begin(),ivector.end(),4)<<endl;
//找出ivector之中大于2的第一个元素所在位置的元素
cout<<*find_if(ivector.begin(),ivector.end(),bind2nd(greater<int>(),2))
<<endl;
//找出ivector之中子序列ivector1所出现的最后一个位置,再往后3个位置的元素
cout<<*(find_end(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end())+3)<<endl;
//找出ivector之中子序列ivector1所出现的第一个位置,再往后3个位置的元素
cout<<*(find_first_of(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end())+3)<<endl;
//子序列ivector2在ivector中出现的起点位置元素
cout<<*search(ivector.begin(),ivector.end(),ivector2.begin(),ivector2.end())
<<endl;
//查找连续出现3个6的起点位置元素
cout<<*search_n(ivector.begin(),ivector.end(),3,6,equal_to<int>())<<endl;
//判断两个区间ivector和ivector3相等否(0为假,1为真)
cout << equal(ivector.begin(), ivector.end(), ivector3.begin()) << endl;
//查找区间ivector3在ivector中不匹配点的位置
pair<int*,int*>result=mismatch(ivector.begin(),ivector.end(),ivector3.begin());
cout<< result.first - ivector.begin() << endl;
}
//6-2.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
class even_by_two{ //类定义形式的函数对象
public:
int operator()() const
{return _x+=2;}
private:
static int _x;
};
int even_by_two::_x=0; //静态数据成员初始化
int main()
{
int iarray[]={0,1,2,3,4,5,6,6,6,7,8};
int iarray1[]={0,1,2,3,4,4,5,5,6,6,6,6,6,7,8};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
vector<int> ivector1(iarray+6,iarray+8);
vector<int> ivector2(iarray1,iarray1+sizeof(iarray1)/sizeof(int));
ostream_iterator< int > output( cout, " " ); //定义流迭代器用于输出数据
//迭代遍历ivector1区间,对每一个元素进行even_by_two操作
generate(ivector1.begin(),ivector1.end(),even_by_two());
copy(ivector1.begin(),ivector1.end(),output);
cout<<endl;
//迭代遍历ivector的指定区间(起点和长度),对每一个元素进行even_by_two操作
generate_n(ivector.begin(),3,even_by_two());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//删除元素6
remove(ivector.begin(),ivector.end(),6);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//删除(实际并未从原序列中删除)元素6,结果置于另一个区间
vector<int> ivector3(12);
remove_copy(ivector.begin(),ivector.end(),ivector3.begin(),6);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//删除(实际并未从原序列中删除)小于6的元素
remove_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),6));
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//删除(实际并未从原序列中删除)小于7的元素,结果置于另一个区间,
remove_copy_if(ivector.begin(),ivector.end(),ivector3.begin(),
bind2nd(less<int>(),7));
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//将所有的元素值6,改为元素值3
replace(ivector.begin(),ivector.end(),6,3);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//将所有的元素值3,改为元素值5,结果放置到另一个区间
replace_copy(ivector.begin(),ivector.end(),ivector3.begin(),3,5);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//将所有小于5的元素值,改为元素值2
replace_if(ivector.begin(),ivector.end(),bind2nd(less<int>(),5),2);
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//将所有的元素值8,改为元素值9,结果放置到另一个区间
replace_copy_if(ivector.begin(),ivector.end(),ivector3.begin(),
bind2nd(equal_to<int>(),8),9);
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//逆向重排每一个元素
reverse(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//逆向重排每一个元素,结果置于另一个区间
reverse_copy(ivector.begin(),ivector.end(),ivector3.begin());
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
//旋转(互换元素)[first,middle), 和[middle,end)
rotate(ivector.begin(),ivector.begin()+4,ivector.end());
copy(ivector.begin(),ivector.end(),output);
cout<<endl;
//旋转(互换元素)[first,middle], 和[middle,end],结果置于另一个区间,
rotate_copy(ivector.begin(),ivector.begin()+5,ivector.end(),
ivector3.begin());
copy(ivector3.begin(),ivector3.end(),output);
cout<<endl;
}
//6-3.cpp
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={26,17,15,22,23,33,32,40};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
// 查找并输出最大、最小值元素
cout<<*max_element(ivector.begin(),ivector.end())<<endl;
cout<<*min_element(ivector.begin(),ivector.end())<<endl;
//将ivector.begin()+4-ivector.begin()各元素排序,
//放进[ivector.begin(),ivector.begin()+4]区间。剩余元素不保证维持原来相对次序
partial_sort(ivector.begin(),ivector.begin()+3,ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//局部排序并复制到别处
vector<int> ivector1(5);
partial_sort_copy(ivector.begin(),ivector.end(),ivector1.begin(),
ivector1.end());
copy(ivector1.begin(),ivector1.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//排序,缺省为递增。
sort(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//将指定元素插入到区间内不影响区间原来排序的最低、最高位置
cout<<*lower_bound(ivector.begin(),ivector.end(),24)<<endl;
cout<<*upper_bound(ivector.begin(),ivector.end(),24)<<endl;
//对于有序区间,可以用二分查找方法寻找某个元素
cout<<binary_search(ivector.begin(),ivector.end(),33)<<endl;
cout<<binary_search(ivector.begin(),ivector.end(),34)<<endl;
//下一个排列组合
next_permutation(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//上一个排列组合
prev_permutation(ivector.begin(),ivector.end());
copy(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//合并两个序列ivector和ivector1,并将结果放到ivector2中
vector<int> ivector2(13);
merge(ivector.begin(),ivector.end(),ivector1.begin(),ivector1.end(),
ivector2.begin());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//将小于*(ivector.begin()+5)的元素放置在该元素之左
//其余置于该元素之右。不保证维持原有的相对位置
nth_element(ivector2.begin(),ivector2.begin()+5,ivector2.end());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//排序,并保持原来相对位置
stable_sort(ivector2.begin(),ivector2.end());
copy(ivector2.begin(),ivector2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//针对一个有序区间,找出其中一个子区间,其中每个元素都与某特定元素值相同
pair<vector<int>::iterator,vector<int>::iterator> pairIte;
pairIte=equal_range(ivector2.begin(),ivector2.end(),22);
cout<<*(pairIte.first)<<endl;
cout<<*(pairIte.second)<<endl;
//合并两个有序序列,然后就地替换
int iarray3[] = { 1, 3, 5, 7, 2, 4, 6, 8 };
vector<int> ivector3(iarray3,iarray3+sizeof(iarray3)/sizeof(int));
inplace_merge(ivector3.begin(), ivector3.begin()+ 4, ivector3.end());
copy(ivector3.begin(),ivector3.end(), ostream_iterator<int>(cout, " "));
cout<<endl;
//以字典顺序比较序列ivector3和ivector4
int iarray4[] = { 1, 3, 5, 7,1, 5, 9, 3 };
vector<int> ivector4(iarray4,iarray4+sizeof(iarray4)/sizeof(int));
cout<< lexicographical_compare(ivector3.begin(),ivector3.end(),
ivector4.begin(),ivector4.end()) << endl;
}
//6-4.cpp
#include <iostream>
#include <numeric>
#include <functional>
#include <vector>
using namespace std;
int main()
{
int iarray[]={1,2,3,4,5};
vector<int> ivector(iarray,iarray+sizeof(iarray)/sizeof(int));
//元素的累计
cout<<accumulate(ivector.begin(),ivector.end(),0)<<endl;
//向量的内积
cout<<inner_product(ivector.begin(),ivector.end(),ivector.begin(),10)<<endl;
//向量容器中元素局部求和
partial_sum(ivector.begin(),ivector.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//向量容器中相邻元素的差值
adjacent_difference(ivector.begin(),ivector.end(),
ostream_iterator<int>(cout," "));
cout<<endl;
}
7、函数对象:一个行为类似于函数的对象,它可以没有参数,也可以带有若干参数,其功能是获取一个值,或者改变操作的状态。任何普通的函数和任何重载了调用运算符operate()的类的对象都满足函数对象的特征,STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。