泛型算法(对容器,内置数组类型或者其他类型的序列的操作):
标准库提供了100多种算法,泛型算法本身从不知形容其操作,只是单独依赖迭代器和迭代器操作实现,算法从不直接添加或删除元素,借刀杀人。所以参数大多包括一段范围元素,即一对迭代器。
使用泛型算法必须: #include<algorithm>
同时标准库还定义了一组泛化的算术算法: #include <numeric>
只读算法
vector <int> vec;
find:
例子:
vector<int>::const_iterator iter = find(vec.begin(), vec.end(), 22);
//在vec查找22,返回指向值为22的const迭代器,不存在则返回vec.end()。
find_first_of(算法的_if版本):
find_first_of带有两对迭代器,再第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,只想第一个匹配的元素,如果找不到,只返回第一个范围的end迭代器。//并不是.end()
例子:
1 list<string> roster1;
2
3 vector<char*>roster2
4
5 ….other
6
7 list<string>::iterator it = roster1.begin();
8
9 while ((it = find_first_of(it, roster1.end(), roster2.begin(), roster2.end()) != roster1.end())
10
11 {
12
13 other …
14
15 };
每对迭代器的类型必须精确匹配,但是两对迭代器之间不需要,只要元素可以用 == 比较即可,
accumulate:
accumulate函数中有一个局部变量,初值为第三个参数,然后累加输入范围内所有元素的值,最后返回此局部变量。
返回值类型为第三个参数类型,且容器内的值需和第三个参数类型相同或者可以转换。
例子:#include <numeric>
int sum = accumulate(vec.begin(), vec.end(), 42); //
写入容器算法
fiil 函数:
输入范围有效时,将第三个形参的副本写入一对迭代器指向的输入范围。
例子:
fill(vec.begin(), vec.end(), 0);
fill_n函数:
三个参数,一个迭代器,一个计数器,一个值,从迭代器指向的元素开始将指定数量的元素设置为给定的值,函数假设写入安全,不可在空的容器上调用此函数。
例子:
vector<int> vec;
fill_n(vec.begin(), 10, 0); //error
back_inserter(生成可以给基础容器添加元素的迭代器):
#include<iterator>
用迭代器给容器元素赋值时,被赋值的是迭代器所指向的元素(相当于覆盖),使用插入迭代器赋值是,则会在容器中添加一个新元素,其值等于赋值运算的右操作数的值。
back_inserter函数式迭代器适配器,以一个对象为实参,生成其实参行为的新对象,生成绑定在该容器上的插入迭代器,实质上,再通过这个迭代器给元素赋值时,赋值运算将调用push_back在容器中添加一个具有指定值的元素。
例子:
fill_n(back_inserter(vec), 10, 0);
写入目标迭代器的算法(元素个数未知):
copy函数:
参数为三个迭代器,头两个指定输入范围,第三个指向目标序列的一个元素,目标序列必须至少要与输入范围一样大(容器足够大),写入的是副本。
例子:
1 list<int> ilst;
2
3 other…
4
5 vector<int>vec;
6
7 copy(ilst.begin(), ilst.end(), back_inserter(ivec));
算法的_copy版本:
例子:
replace算法:将一对迭代器指向的范围内的值为第三个形参的元素替换成第四个元素;
replace(ilst.begin(), ilst.end(), 0, 42);
如果不想改变ilst序列,可以用_copy版本:
replace_copy(ilst.begin(), ilst.end(), back_inserter(vec), 0, 42); //ilst没有变,vec为ilst的副本,不过再vec中所有的0替换为42;
1 hi hi effective stl stl
2
3 sort(word.begin(), words.end()); //effective hi hi stl stl
4
5 vector<string>::iterator end_unique = unique(words.begin(), words.end()); // effective hi stl hi stl
6
7 word.erase(end_unique, word.end()); //删除hi及后面的元素
sort 函数:
带有两个迭代器实参,用<操作符比较元素,排列元素。
unique函数:
去除相邻的重复元素,然后重新排列输入范围内的元素,返回一个迭代器,指向无重复的值范围结束。(指向hi),实际上并未删除
stable_sort函数:
参数为一对迭代器和一个谓词函数(做某些检测的函数,返回用于条件判断的类型,指出条件是否成立)。
例子:
1 bool isshorter(const string &str1, const string &str2)
2
3 {
4
5 return str1.size() < str2.size();
6
7 }
8
9 stable_sort(word.begin(), word.end(), isshorter);
count_if 函数:
返回谓词函数返回条件成立的元素个数
例子:
1 bool GT6(const string &str)
2
3 {
4
5 return str.size() >= 6;
6
7 }
8
9 vector<string>::size_type vc = count_if(word.begin(), word.end(), GT6);
再谈迭代器
#include <iterator>
插入迭代器 与容器绑定实现在容器中插入元素的功能
iostream迭代器 与输入输出流绑定,用于迭代遍历所关联的流。
反向迭代器 实现向后遍历
const 迭代器 不能通过迭代器修改容器内元素
插入迭代器
功能如上面。
1) back_inserter 创建使用push_back实现插入的迭代器
2) front_inserter 创建使用push_front实现插入的迭代器
3) inserter 使用insert实现插入,第二个实参为指向插入位置的迭代器
例子:
list<int>::iterator it = find(ilst.befin(), ilst.end(), 42);
replace_copy(ivec.befin(), ivec.end(), inserter<ilst, it>, 100, 0>;
iostream流迭代器(将它们所对应的流视为特定类型的元素序列):
流迭代器是模板,对任何已定义>>输入操作符的类型都可以定义istream_iterator,同理,对任何已定义<<输出操作符的类型都可以定义ostream _iterator。
istream_iterator迭代器 用于读取输入流
ostream_iterator 用于写输出流,不可写入,对象中每个不同的值只能输出一次。
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对象,再写入过程中以(以null结尾的字符数组)delim做为分隔符,否则行为未定义
例子:
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_it;
ofstream outfile;
ostream_iterator<int> output(outfile, “”);
istream_iterator才有比较运算:
it1 == it2; 迭代器读取的必须是相同的类型
it1 != it2; 如果两个迭代器都是end值则相等,对于两个都不指向流结束位置的迭代器,如果他们使用同一个输入流构造,则它们也相等
istream_iterator和ostream_iterator都可以有的运算(解引用,自增,赋值):
*it; 解引用,返回从流中读取的值ostream_iterator只能使用一次
it->mem 同(*it).mem,但是ostream_iterator不能有
++it; it++ ; //通过使用元素类型提供的>>操作符从输入流中读取下一个元素值,是迭代器向前移动。通常,前缀版本使迭代器在流中向前移动,并返回对加1后的迭代器的引用。而后缀版本使迭代器在流中向前移动后,返回原值。
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_it;
while (cin_in != end_it) //文件结束或者遇到错误时成立
{
vec.push_back(*cin_it++);
}
或者可以这样
vec.assign(cin_it, end_it);
反向迭代器(反向遍历容器的迭代器):
reverse_iterator
++将访问前一个元素,--将访问下一个元素。
const 迭代器
const 迭代器和非const迭代器类型不一样
如果容器是const对象,则返回的迭代器要是const迭代器
关联容器的键是const对象
map,set,list类型提供双向迭代器,string,vector和deque提供随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器,istream_iterator是输入迭代器,ostream_iterator则是输出迭代器。
容器特有的算法:
list 不能使用随机访问迭代器的算法,包括sort及其相关算法,而merge,remove,reverse,unique再list上使用会有性能上的代价,list有其特有的操作。
如:lst.merge(lst2); //lst2合并到lst,两个容器必须排序,之后lst2为空,返回void
lst.remove(val); //调用lst.erase删除等于val的元素
lst.remove_if(unarypred); //调用lst.erase删除会使谓词函数unarypred返回非零的元素
lst.sort(); //对lst中的元素排序
lst.reverse(); //反向排列lst中的元素
lst.splice(iter, lst2); //将lst2中的元素放置到lst中iter指向的元素前,lst2置空
lst.splice(iter, lst2, iter2); //将lst2中iter2指向的元素放置到lst中iter指向的元素前,lst, lst2可以是同一个list对象
lst.splice(iter, b, e); //将[b, e)指向的元素放置到lst中iter指向的元素前,如果iter也指向这个范围,则结果未定义
lst.unique(); //调用lst.erase删除同一个值的连续副本,用 == 判断是否相等
lst.unique(binaryPred); //调用lst.erase删除同一个值的连续副本,用 谓词函数binaryPred返回值判断
算法:
sort: 完全排序,
而partial_sort 算法则可以部分排序,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?