C++primer -泛型算法

泛型算法是使用容器的迭代器实现的与容器类型无关的一系列通用算法。与容器无关是指,泛型算法对所有容器都适用(部分泛型算法要求容器的迭代器或元素支持一些操作)。

大部分泛型算法定义在头文件<algorithm>中,部分定义在<numeric> 中。

泛型算法的操作对象往往是一个迭代器范围(本笔记将其称为迭代器序列,即从迭代器b到迭代器e及其中间的元素组成的序列,区间左闭右开,用[b, e)表示),但泛型算法对操作对象的使用方式不同,导致泛型算法要求迭代器所支持的操作也不同。了解泛型算法一般需要了解:泛型算法是否读取元素、重排元素、改变元素。

根据泛型算法涉及的基础操作,将泛型算法分为几种:

1、只读算法:

只读算法是对容器的元素只读(不做修改,没有赋值/改变元素次序/删除/添加元素)的算法。对于只读算法最好使用cbegin(), cend()返回的const_iterator类型的迭代器。

  • accumulate(b, e, initVal) : 累加算法,将迭代器所指范围的元素累加,可设置一个初值initVal,累加结果的对象类型以初值的类型推断为依据,并使用初值类型对应的加法运算符。

注意:初值必须有加法运算符定义,如:accumulate(b, e,  " ");  // 错误,C风格字符串" "没有加法运算。

  • equal(b1, e1, b2) :  比较两迭代器序列指向内容是否相等,要求元素必须有相等运算符,[b1, e1)表示第一个容器的一个迭代器序列,b2表示第二个容器从b2开始到end()的序列。

注意,equal对第二个容器只用一个迭代器表示第二个序列,它要求第二个序列必须比第一个序列长。对单一迭代器表示的第二个序列,都要求第二个序列比第一个长。

  • equal_range(b, e, val, equal_callable) : 在元素有序的[b, e) 迭代器序列内查找值等于val的元素(即取第一个等于val的到第一个大于val的之间的元素),equal_callable是用于判定对象是否等于val的可调用对象,可省略,默认为使用==。函数返回一个pair,其first为第一个等于val的元素的迭代器,second为第一个大于val的元素的迭代器。
  • find(b, e, key) : 查找值为key的元素,若元素存在,返回其迭代器,否则返回end();
  • find_if(b, e, pred) : 查找使条件为真的元素。pred为一元谓词,可以是一个函数对象或一个可执行的代码单元,一元表示其接受一个参数,find_if将迭代器序列中的每一个元素作为pred的参数,要求pred返回一个bool值,最后find_if返回使bool值为真的第一个元素。如希望返回第一个bool值为假的元素,使用find_if_not
  • find_end(b, e, b2, e2) : 返回序列[b2, e2)在序列[b, e)中最后一次出现的位置。

插入迭代器:

对插入迭代器赋值会在插入迭代器所指位置创建赋值的元素的拷贝。

插入迭代器的作用是将赋值改为插入,将泛型算法中的修改变为写入。

以下函数会返回一个插入迭代器:

back_inserter(c) : 接受一个容器对象c(引用传递),返回一个与该容器绑定的插入迭代器,对该插入迭代器赋值能将赋值符号右侧内容的拷贝插入到队尾(执行的是push_back)。

inserter(c, p) : 接受一个容器对象c和迭代器p,返回一个与该容器绑定的插入迭代器,对该插入迭代器赋值,会将值的拷贝插入到迭代器所指位置之前(执行的是insert)

front_inserter(c):接受一个容器对象c,返回一个与该容器绑定的插入迭代器,对该插入迭代器赋值会将值的拷贝插入到容器的首位(执行的是push_front)

2、写容器元素算法:

  • fill(b, e, val) : 作用:填充,将[b, e)范围内的每个元素都赋值为val,不检查序列的有效性,因此需要保证给定序列不能越界
  • fill_n(b, n, val) : fill的指定元素个数版本,用val填充b所指元素及之后的n个元素值。
  • copy(b, e, b2) : 将[b, e)的内容拷贝赋值给b2中的对应元素,返回b2的最后一个赋值元素之后的迭代器。
  • copy_n(b, n, b2) : 将b及之后的n个元素插入到b2中
  • replace(b, e, val1, val2) : 将迭代器序列中元素值为val1的元素替换为val2
  • replace_copy(b, e, b2, val1, val2) : 将迭代器序列的内容先拷贝到b2中再将val1替换为val2(不改变原序列)
  • replace_if(b, e, pred, val) : 条件pred为真时替换元素值为val
  • replace_copy_if(b, e, b2, pred, val): 将序列[b, e)中使pred返回真的元素值改为val再复制到目的序列b2中
  • merge(b, e, b2, e2, dest):将有序序列[b,e)和有序序列[b2, e2)合并为一个新的有序序列,并插入到dest所指的位置,返回新序列中插入的最后一个元素之后位置的迭代器,通用版本的merge是拷贝插入,输入的两个序列元素不改变。
  • merge(b, e, b2, e2, dest, comp) : 自定义排序规则的merge
  • inplace_merge(first, mid, last) : first, mid, last是同一序列中的迭代器,将[first, mid)和[mid, last) 按序合并,同样有自定义排序规则的版本。

对于fill和copy这类修改容器中元素值的泛型算法,可以使用插入迭代器,将 填充/拷贝容器对象中的元素 的操作 变为 插入元素到容器对象中 的操作:

fill_n(back_inserter(c), n, val); // 向容器c尾部插入n个值为val的元素。

copy(b, e, inserter(c, p)); // 向容器c的p迭代器所指位置之后,插入[b, e)所表示的序列中的元素。

泛型算法后缀:_if (满足条件则执行操作), _copy (将序列复制到目的序列),_n (使用首元素加长度的格式表示迭代器序列)

谓词:

什么是谓词?谓词是一个 返回条件值(true或false、或能转为true or false的值)的可调用的表达式。可调用的 表示该对象支持() 调用运算符,支持调用运算符的有三类:a. 函数及函数指针、b. 重载了调用运算符的类对象、c. lambda表达式。标准库算法所使用的谓词分为:一元谓词和二元谓词,元表示可调用表达式接受几个参数。

3、重排元素算法:

  • sort(b, e): 用 < 重排容器元素,改变元素次序但不改变元素值。要求元素必须支持 < 运算符。sort算法不能用于listforward_list
  • sort(b, e, pred) :pred是二元谓词,即接收两个参数的、返回条件值的可调用表达式,接受两个相邻的元素作为参数,返回结果为假则改变其次序,直到整个序列都返回真。通常可以设置pred为less<T>\greater<T>

           例:以下代码将words容器中的元素按字符串从短到长排列:

                bool isShorter(string s1, string s2){return s1.size() < s2.size();}  

                sort(words.begin(), words.end(), isShorter);

  • unique(b, e) : 删除值连续出现元素的副本,只保留第一次出现的, 并返回去重后最后一个元素的地址,如:val1连续出现了两次,那么删除第二个值为val1的元素(实际上将重复元素放到去重后序列的后面),只保留第一个, 一般要求序列有序。
  • stable_sort(b, e) : 稳定排序,对于优先级相等的元素,不改变其原有次序,如 若元素A与B相等,排序前A在B之前,那么排序后A仍在B之前。

注意:如果使用反向迭代器,会使泛型算法按反向操作,如sort会从尾到头排序序列。

list和forward_list特有的算法:

由于链表可以通过改变元素间的链接而提高交换元素的效率,所以标准库定义了链表特有的更高效的一些成员函数,若通用算法和链表的成员函数功能重合,那么尽量考虑链表的成员函数。

list和forward_list特有的成员函数如下(以下函数都不返回):

merge:

  • lst.merge(lst2);// 将有序序列 lst 与有序序列 lst2 合并到 lst, lst2中的元素将被删除, 函数不返回,比较符号使用<。
  • lst.merge(lst2, comp); // 指定比较函数的版本,不返回

remove 和 reverse:

  • lst.remove(val); // 移除lst中值为val的每个元素,不返回
  • lst.remove_if(pred); // 移除lst中使pred返回条件为真的元素,不返回
  • lst.reverse(); // 反转lst中的元素的顺序 ,不返回。

sort和unique:

  • lst.sort();// 使用<排列元素, 不返回。
  • lst.sort(comp);// 使用指定的二元谓词comp排序元素。
  • lst.unique(); // 将lst中连续出现的元素除第一个外,删除(即若元素在序列中出现两次以上,则只保留第一次的版本)返回去重后的最后一个元素的迭代器,一般要求序列有序,成员函数版本使用erase删除元素副本。
  • lst.unique(pred); // 将连续满足条件pred的元素,只保留第一个,删除之后的。

slipce:

  • lst.slipce(p, lst2); // 将lst2中的元素剪切到p所指的元素之前,lst2中的元素被删除。
  • lst.slipce(p, lst2, p2); // 仅将lst2中p2所指的元素剪切到p所指的元素之前,p2所指元素被删除。
  • lst.slipce(p, lst2, b2, e2); // 将lst2中[b2, e2)范围内的元素剪切到p所指的元素之前,lst2中[b2, e2)的元素被删除。
  • flst.slipce_after(p, lst2); // 将lst2中的元素剪切到p所指元素之后,与lst.splice(p, lst2)不同的是将元素剪切到flst之后。。
  • flst.slipce_after(p, lst2, p2); //  将lst2中p2所指元素剪切到p所指元素之后,p2所指元素被删除。
  • flst.slipce_after(p, lst2, b2, e2); // 与lst.splice(p, lst2, b2, e2)不同的是将元素剪切到flst之后。
  • 61
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值