1. 在大多数情况下,每个算法都需要使用(至少)两个迭代器来指出该算法操纵的元素范围,第一个迭代器指向第一个元素,而第二个迭代器则指向最后一个元素的下一个位置.第二个迭代器(有时也被称为超出末端迭代器)所指向的元素本身不是要操作的元素,而被用作终止遍历的哨兵.
2. 算法永不执行容器提供的操作;泛型算本身从不执行容器的操作,只是单独依赖迭代器和迭代器操作的实现
3. 泛型算法必须包含: #include <algorithm>
标准库还定义了一种泛化的算术算法,其命名习惯与泛型算法相同.使用它们时,要包含如下头文件: #include <numeric>.
除了少数算法外,所有算法都在一段范围内的元素上操作,我们将这段范围称为”输入范围”.(他们总是指向要处理的第一个元素和最后一个元素的下一个位置的迭代器),另外理解这些算法的最基本的方法是了解该算法是否读元素,写元素,或者对元素进行重新排序.
4.常见的泛型算法:
◆find(beg,end,val)//查找从beg到end中值为val的元素,如果找到,则返回该元素对应的迭代器,否则返回end
◆accumulate(beg,end,val)//将beg到end之间的元素相加,并加上val.返回累加的结果.( 用于指定累加起始值的第三个实参是必要的,因为accumulate对将要累加的元素类型一无所知.)
◆find_first_of(beg1,end1,beg,end)//查找beg1到end1之间的元素出现在beg到end的个数,查找成功,返回一个指向第一个匹配的元素的迭代器,否则返回第一个范围的end迭代器(这句根据我的理解是,返回需查找的元素本身的迭代器).在这里有<C++ Primer>中的例子为证:
vector<string>vect_string;
vect_string.push_back("liming");
vect_string.push_back("andy");
vect_string.push_back("zhangxueyou");
vect_string.push_back("guofucheng");
string person_Name;
vector<string>vect_other_string;
while (cin>>person_Name)
{
vect_other_string.push_back(person_Name);
}
int count = 0;
vector<string>::iterator iter = vect_string.begin();
while ((iter = (find_first_of(iter,vect_string.end(),vect_other_string.begin(),vect_other_string.end()))) != vect_string.end())
{
iter++;
count++;
}
cout<<"相同元素的个数为:"<<count<<endl;
假设输入为:
chenglong
andy
ctrl+z程序将会返回:相同元素的个数为:1
注意:这里需要重点说明的一点是:假若我们第一次输入的元素不在vect中则返回end,则循环结束.就没有必要继续对比.也就不会输出”相同元素个数为:1”,因此,如果我们把它理解为返回当前元素就可以得到结果.(这里只是我个人的理解,欢迎拍砖)
◆fill(beg,end,val)//初始化beg到end的元素为val
注意:对于指定数目的元素做写入运算,或者写到目标迭代器的算法,都不检查目标的大小是否足以存储要写入的元素
确保算法有足够的元素存储输出数据的一种方法是使用插入迭代器.插入迭代器是可以给基础容器添加元素的迭代器.
◆back_inserter(vec)//生成一个绑定在该容器上的插入迭代器.
◆sort(beg,end)//对beg到end的元素进行排序
◆unique(beg,end)//删除相邻的重复的元素,然后重新排列输入范围内的元素,并返回迭代器,表示无重复值范围的结束
注意:算法不直接改变容器的大小.如果需要添加或删除元素,则必须使用容器操作
◆stable_sort(beg,end,fun)://将 beg到end的元素按照fun函数约定的规则进行排序其中fun必须接受两个参数.
◆connt_if(beg,end,fun)//将beg到end的元素按照fun函数的约定进行排序,fun函数必须是具有单个元素类型的实参.返一个使得条件成立的个数
◆fill_n(back_insert(vec),10,0)//在vec的末尾添加10个值为0的元素
◆replace(beg,end,val1,val2)//将beg到end的区域中的val1的值替换为val2值
◆replace_copy(beg,end,back_insert(vec),val1,val2)//将beg到end区域值为val1的值替换为val2,并插入至vec中.
举例:
list<int>ilst;
for (list<int>::size_type ix = 0; ix <= 9;ix++)
{
ilst.push_back(ix);
ilst.push_back(ix);
}
vector<int>ivec;
ivec.push_back(100);
replace_copy(ilst.begin(),ilst.end(),back_inserter(ivec),0,42);
int i = 0;
for (vector<int>::iterator iter = ivec.begin();iter != ivec.end(); iter++)
{
cout<<"该vector的第"<<i++<<"个元素的值为:"<<*iter<<endl;
}
5.C++语言提供了三种迭代器,其差别在于插入元素的位置不同.
①.back_inserter,创建使用push_back实现插入的迭代器
②.front_inserter,使用push_front实现插入迭代器
③.inserter,使用insert实现插入操作,除了所关联的容器外,inserter还带有第二个实参,:指向插入起始位置的迭代器
注意:只有当容器提供push_front操作时,才能使用front_inserter,在vector或其他没有提供push_front操作的容器上使用时将会发生错误
front_inserter与inserter的本质区别:
list<int>ilst1,ilst2,ilst3;
for(list<int>::size_type i= 0;I != 4;++i)
{
ilst1.push_front(i);
}
前者总是在容器的所有元素之前插入,而后者则是在前面插入一个与元素后,元素首位置改变了.
6.iostream迭代器
istream_iterator<T>in(strm) 创建从输入流strm中读取T类型对象的istream_iterator对象
istream_iterator<T>in istream_iterator对象的超出末端的迭代器
ostream_iterator<T>in(strm) 创建将T类型的对象写到输出流strm的ostream_iterator对象
ostream_iterator<T>in(strm,delim) 创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分隔符.delim是以空字符结束的字符数组
注意:迭代器只提供了最基本的迭代器操作:自增,解引用和赋值.此外还可以比较两个istream迭代器是否相等(或不等).而ostream迭代器则不提供比较运算
举例:
istream_iterator<int>in_iter(cin);
istream_iterator<int>in;
vector<int>vec;
while (in_iter != in)
{
vec.push_back(*in_iter++);
}
7.ostream_iterator对象和istream_iterator对象的使用:
ostream_iterator<string>out_iter(cout,"/n");
istream_iterator<string>in_iter(cin),eof;
while (in_iter != eof)
{
*out_iter++ = *in_iter++;
}
8.流迭代器的限制:
1).不可能将ostream_iterator对象读入,也不可能写到istream_iterator对象中.
2).一旦给ostream_iterator对象赋了一个值,写入就提交了.赋值后,没有办法在改变这个值.此外,ostream_iterator对象中的每个值都正好只能输出一次
3).ostream_iterator没有->操作符.
9.反向迭代器:
vec.begin() |
vec.end() |
|
|
|
|
|
|
|
vec.rbegin() |
vec.rend() |
① 从一个即支持—也支持++的迭代器就可以定义反向迭代器.
② 流式迭代器由于不能使用反向迭代器
③ 使用普通迭代器对反向迭代器进行初始化或赋值时,所得到的迭代器并不是指向原迭代器所指向的元素
10.五种迭代器:
①输入迭代器:读,不能写;只能支持自增运算
②输出迭代器:写,不能读;只能支持自增运算
④ 前向迭代器:读和写,只能支持自增操作运算
⑤ 双向迭代器:读和写,支持自增和自减运算
⑥ 随机访问迭代器:读和写,支持完整的迭代器算术运算