C++泛型算法

泛型算法

  • 大多数算法都定义在头文件algorithm,标准库在在头文件numeric中定义一组数值泛型算法
  • 一般算法并不直接操作容器,而是遍历由两个迭代器指定的一个元素范围操作(输入范围)

初识泛型算法

只读算法

  • 只读取其输入范围内的元素,不改变元素
  • find
  • accumulate包含在numeric
  • equal用于确定两个序列是否保存相同的值
int sum = accumulate(vec.cbegin(),vec.cend(),0);
//前两个参数指出了需要求和的元素的范围,第三个参数是和的初值
//第三个参数的类型决定了函数中使用哪个加法运算符以及返回值的类型,即序列中元素的类型必须与第三个参数匹配或能够转换尾第三个参数的类型
算法和元素类型
string sum = accumulate(v.cbegin(),v.cend(),string(""));
//string初始化为空串,通过第三个参数显式创建了一个string

//将空串当做一个字符串字面值传递给第三个参数是不可以的,会导致编译错误
//string sum = accumulate(v.cbegin(),v.cend(),"");
//传递字符串字面值,用于保存和的对象是const char*,const char*没有+运算符,此调用将产生编译错误
操作两个序列的算法
equal(roster1.cgegin(),roster1.cend(),roster2.cbegin());
//roster2中的元素数目应该至少和roster1一样多,元素类型不必一样

写容器元素的算法

  • 一些算法将新值赋予序列中的元素,必须保证序列原大小至少不小于要求算法写入的元素数目,算法不会执行容器操作,不可能改变容器大小
//fill接受一对迭代器表示一个范围,接受一个值作为第三个参数,fill将给定的这个值赋予输入序列中的每个元素
fill(vec.begin(),vec.end(),0);
算法不检查写操作
vector<int>vec;
//fill_n(vec,begin(),10,0);
//修改vec中的10个(不存在)的元素,这条语句结果是未定义的
back_inserter
  • 头文件iterator
  • 接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中
vector<int>vec;
auto it = back_insert(vec);//通过它赋值会将元素添加到vec中
*it = 42;//vec中现在有一个元素为42

//使用back_instertrt创建一个迭代器作为算法的目的位置使用
fill_n(back_inserter(vec),10,0);
//会调用push_back,添加10个元素到vec
拷贝算法
int a1[]={0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)];
//ret指向拷贝到a2的尾元素之后的位置
auto ret = copy(begin(a1),end(a1),a2);//将a1的内容拷贝给a2

重排容器元素的算法

消除重复单词
void elimDups(vector<string>&words){
    //按字典序排序words,以便查找重复单词
    sort(words.begin(),words.end());
    //unqiue重排输入范围,使得每个单词只出现一次
    //排列在范围的前部,返回指向不重复区域之后一个位置的迭代器
    auto end_unique = unique(words.begin(),words.end());
    //使用向量操作erase删除重复单词
    words.erase(end_unique,words.end());
}

//unique算法重排序列,将向量的重复项消除,并返回一个指向不重复值范围末尾的迭代器。

定制操作

向算法传递函数

谓词
  • 一个可调用的表达式,其返回结果时一个能用作条件的值,标准库算法使用的谓词有两类
    • 一元谓词:只接受单一参数
    • 二元谓词:接受两个参数
//比较函数,用来按长度排序单词
bool isShorter(const string &s1,const string &s2){
    return s1.size()<s2.size();
}
//按长度由短至长排序words
sort(words.begin(),words.end(),isShorter);
排序算法
  • satble_sort为保持相同长度的单词按字典序排序
elimDups(words);//将words按字典序重排并消除重复单词
//按长度重新排序,长度相同的单词维持字典序
stable_sort(words.begin(),words.end(),isShorter);
for(const auto &s:words)//无需拷贝字符串
    cout<<s<<" ";
cout<<endl;

lambda表达式

void biggies(vector<string>&words,vector<string>::size_type sz)
{
    elimDups(words);
    stable_sort(words.begin(),words.end(),isShorter);
    //获取一个爹大气,指向第一个满足size()>=sz的元素
    //计算满足size>=sz的元素的数目
    //打印长度大于等于给定值的单词,每个单词后面接一个空格
}
介绍lambda
  • 可以向一个算法传递任何类别的可调用对象。对于一个对象或一个表达式,如果可以对其使用调用运算符,则称它为可调用的
//[capture](parameter list) ->return type{function body}
//capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表(通常为空)
//return type、parameter list和function body与任何普通函数一样,分别表示返回类型、参数列表、函数体。与普通函数不同,lambda必须使用尾置返回指定返回类型

auto f = []{return 42;};
//定义一个可调用对象f,不接受参数,返回42
cout<<f()<<endl;//打印42
向lambda传递参数
  • lambda不能有默认参数
stable_sort(words.begin(),words.end(),[](const string &a,const string &b)
{return a.size()<b.size();});
使用捕获列表
  • 通过将局部变量包含在其捕获列表中来指出将会使用这些变量
[sz](const string &a){retur  a.size()>=sz;};

lambda捕获和返回

  • 当定义一个lambda时,编译器生成一个与lambda对应的新的(未命名的)类类型
值捕获
  • 被捕获的变量的值时在lambda创建时拷贝,而不是调用时拷贝
void fcn1(){
    size_t v1 = 42;//局部变量
    //将v1拷贝到名为f的可调用对象
    auto f = [v1]{return v1;};
    v1 = 0;
    auto j = f();//j=42
}
引用捕获
void fcn2(){
    size_t v1=42;
    auto f2 = [&v1]{return v1};
    v1 = 0;
    auto j = f2();//0
}
隐式捕获
  • 编译器根据lambda体中的代码推断出需要使用哪些变量。
  • 为了指示编译器推断捕获列表,应在捕获列表中写**&=**
  • &:引用捕获
  • =:值捕获
wc = find_if(words.begin(),words.end(),[=]{const string &s}{return s.size()>=sz;});
可变lambda
  • 改变一个被捕获的变量的值,在参数列表首加关键字mutable
void fcn3(){
    size_t v1=42;
    auto f = [v1]()mutable(return ++v1;);
    v1=0;
    auto j = f();//43
}

void fcn4(){
    size_t v1 = 42;
    auto f2=[&v1]{return ++v1;};
    v1=0;
    auto j=f2();//1
}

参数绑定

标准库bind函数
  • 头文件functional
  • 看作一个通用适配器,接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表
//auto newCallable = bind(callable,arg_list);
//newCallable是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数,即调用newCallable是,newCallable会调用callable,并传递给它arg_list中的参数
//arg_list中的参数可能包含形如_n的名字,n是一个整数,这些参数是“占位符”,表示newCallable的参数,占据了传递给newCallable的参数的位置,数值n表示生成的可调用对象中参数的位置:_1位newCallable的第一个参数,_2为第二个
绑定check_size的sz参数
//check6是一个可调用对象,接受一个string类型的参数
auto check6 = bind(check_size,_1,6);
string s = "hello";
bool b1 = check6(s);//调用check_size(s,6)
  • _n定义在placeholders的命名空间中。这个命名空间本身定义在std命名空间中

再探迭代器

插入迭代器

  • 接受一个容器,生成一个迭代器,能实现向给定容器添加元素
//back_inserter
//创建一个使用push_back的迭代器

//front_inserter
//创建一个使用push_front的迭代器

//inserter
//创建一个使用insert的爹大气,此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器,元素将被插入到给定迭代器所表示的元素之前

iostream迭代器

istream_iterator操作
istream_iterator<int>int_it(cin);//从cin读取int
istream_iterator<int>int_eof;//尾后迭代器
ifstream in("afile");
istream_iterator<string>str_it(in);//从“afile"读取字符串

//用istream_iterator从标准流输入读取数据,存入一个vector
istream_iterator<int> in_iter(cin);//从cin读取int
istream_iterator<int> eof;
while(in_iter!=eof)//当有数据可供读取时
    //后置递增运算读取流,返回迭代器的旧值
    //解引用迭代器,获得从流读取的前一个值
    vec.push_back(*in_iter++);
ostream_iterator操作

反向迭代器

泛型算法结构

  • 输入迭代器:可以读取序列中的有元素,只写不读
  • 前向迭代器:可以读写元素,只能再序列中沿一个方向移动
  • 双向迭代器:可以正反向读写元素
  • 随机访问迭代器:提供在常量时间内访问序列中任意元素的能力

特定容器算法

  • list与forward_list
lst.merge(lst2);
lst.merge(lst2.comp);
//将来自lst2的元素合并入lst。lst和lst2都必须是有序的,元素将从lst2中删除,在合并之后,lst2变为空,第一个版本使用<运算符,第二个版本使用给定的比较操作

lst.remove(val);
lst.remove_if(pred);
//调用erase删除掉与给定值相等或令一元谓词为真的每个元素

lst.reverse();
//反转lst中元素的顺序

lst.sort();
lst.sort(comp);
//使用<或给定比较操作排序元素

lst.unique();
lst.unique(pred);
//调用erase删除同一个值的连续拷贝,第一个版本使用==,第二个版本使用给定的二元谓词
  • 链表还定义了splice算法
lst.splice(args)或flst.splice_afrter(args);
(p,lst2);
//p是一个指向lst中元素的迭代器,或指向flst首前位置的迭代器,函数将lst2的所有元素移动到lst中p之前的位置或是flst中p之后的位置,将元素从lst2中删除,lst2可以是与lst或flst相同的链表
    
(p,lst2,p2);
//p2是一个指向lst2中位置的有效的迭代器,将p2指向的元素移动到lst中,或将p2之后的元素移动到flst中,lst2可以是与lst或flst相同的链表

(p,lst2,b,e);
//b和e必须表示lst2中的合法范围,将给定范围中的元素从lst2移动到lst或flst,lst2与lst(或flst)可以是相同的链表,但p不能指向给定范围中元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值