标准库并未给每个容器定义成员函数来实现这些操作,而是定义了一组泛型算法(generic algorithm):称他们为”算法“,是因为他们实现了一些经典算法的公共接口,如排序和搜索:称他们是“泛型的”,是因为它们可以用于不同类型的元素和多种容器类型(不仅包括标准库类型,如vector或list,还包括内置的数组类型),以及我们将看到的,还能用于其他类型的序列。

练习10.3,10.4
#include
<iostream>
#include
<vector>
#include
<numeric>
using
namespace
std;

int
main()
{
            
vector
<
int
> vec;
            
int
i = 0;
            cout <<
"请输入整数"
<< endl;
            
while
(cin >> i)
            {
                        
if
(i == -1)
                                    
break
;
                        vec.push_back(i);
            }
            
int
val;
            cout <<
"请输入你要查找的数字\n"
;
            cin >> val;
            
auto
result = find(vec.cbegin(), vec.cend(), val);
//查找输入的数字是否在容器中,在则显示the value x is present,否则显示the value is not present;
            cout <<
"The value "
<< val << (result == vec.cend() ?
" is not present\n "
:
" is present\n"
) << endl;
//
            cout <<
"accumulate1:"
<< accumulate(vec.cbegin(), vec.cend(), 0)<<endl;
//算出元素之和;
            
vector
<
double
> ivec = { 1.1, 2.2, 3.3, 4.4,5.5 };
            cout <<
"accumulate2:"
<< accumulate(ivec.cbegin(), ivec.cend(), 0.0)<<endl;   //16.5   前面是double,一定要注意用0.0
            
return
0;
}


关键概念:算法永远不会执行容器的操作


慎用内联
内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?
如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的
执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收
获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,
消耗更多的内存空间。以下情况不宜使用内联:
(1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构
函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。
所以不要随便地将构造函数和析构函数的定义体放在类声明中。
一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明
了inline 不应该出现在函数的声明中)。

C++ 语言支持函数内联,其目的是为了提高函数的执行效率(速度)。

重排容器元素的算法(sort)、消除重复单词(unique)、使用容器操作删除元素(erase)
练习:10.9
实现你自己的elimDups。测试你的程序,分别在读取输入后,调用unique后以及调用erase后打印vector。
#include
<iostream>
#include
<vector>
#include
<string>
#include
<algorithm>
using
namespace
std;

void
elimDups(
vector
<
string
> &
vec
)
{
            sort(
vec
.begin(),
vec
.end());
//排序

            
auto
end_unique = unique(
vec
.begin(),
vec
.end());
//重排输入范围,使得每个单词只出现一次,找到重复元素;
            cout <<
"unique after\n"
;

            
for
(
auto
i = 0; i !=
vec
.size(); ++i)
            {
                        cout<<
vec
[i] <<
" "
;
            }
            cout<< endl;
            
vec
.erase(end_unique,
vec
.end());
//删除重复元素
            cout <<
"erase after\n"
;
            
for
(
auto
i = 0; i !=
vec
.size(); ++i)
            {
                        cout <<
vec
[i] <<
" "
;
            }
            cout << endl;
}
int
main()
{
            
string
word;
            
vector
<
string
> vec;
            cout <<
"请输入一串单词(#结束)\n"
;
            
while
(cin >> word)
            {
                        
if
(word ==
"#"
)
                                    
break
;
                        vec.push_back(word);
            }
            elimDups(vec);

            
return
0;
}


lambda 表达式

练习10.16
使用lambda编写你自己版本的biggies.
#include
<iostream>
#include
<string>
#include
<vector>
#include
<algorithm>
using
namespace
std;

void
elimpDups(vector<string> &s)
{
            sort(s.begin(), s.end());
//排序;
            
auto
new_end = unique(s.begin(), s.end());
//找出重复元素;
            s.erase(new_end, s.end());
//删除重复元素;
}
void
biggies(vector<string> &words, vector<string>::size_type sz,ostream &os = cout,
char
c =
' '
)
{
            elimpDups(words);
            stable_sort(words.begin(), words.end(), [](string
const
&lhs, string
const
&rhs){
                        
return
lhs.size() < rhs.size();});
//按长度排序,长度相同的单词维持字典序;
                        
auto
wc = find_if(words.begin(), words.end(), [sz](string
const
&a){
                                    
return
a.size() >= sz;});
//找到满足size >= sz的元素数目;
                                    
/*for_each(wc, words.end(),[](const string &s){
                                                cout << s << " ";});// 打印长度大于等于给定值的单词,每个单词后面接一个空格;
                                                cout << endl;
                                                */
                                    for_each(wc, words.end(), [&os, c](
const
string &s){
                                                os << s << c;});
//加入引用捕获;ostream &os = cout,char c = ' ';
                                                os << endl;
}
void
  fun1()
{
            size_t v1 = 42;
            
auto
f2 = [&v1]{
return
++v1; };
            v1 = 0;
            
auto
j1 = f2();
            cout << j1 << endl;
//j1 = 1;
}
void
fun2()
{
            size_t v1 = 42;
            
auto
f2 = [v1]()
mutable
{
return
++v1; };
            v1 = 0;
            
auto
j2 = f2();
            cout << j2 << endl;
//j2 = 43
}
int
main()
{
            vector<string> vec = {
"1234"
,
"1234"
,
"1234"
,
"hi~"
,
"alan"
,
"alan"
,
"cp"
,
"a"
,
"abc"
};
            biggies(vec,3);
            fun1();
//引用捕获
            fun2();
//变量捕获
            
return
0;

}

默认情况下,对一个被拷贝的变量,lambda不会改变其值,如果我们希望能改变一个被捕获的变量的值,就必须在参数列表首加上关键字mutable。因此,可变的lambda能省略参数列表。


引用捕获



隐示捕获


谓词:
是一个可调用的表达式,其返回结果是一个能用做条件的的值。标准库算法所使用的的谓词分为两类:一元谓词(意味着它只接受单一参数)、二元谓词(意味着它们有两个参数)。


练习10.24:
给定一个string,使用bind和chaeck_size在一个int的vector中查找第一个大于string长度的值。
#include
<iostream>
#include
<vector>
#include
<algorithm>
#include
<string>
#include
<functional>
using
namespace
std;
inline
bool
check_size(
const
string
&
s
,
vector
<
int
>::
size_type
sz
)
{
            
return
s
.size() <
sz
;
}
inline
vector
<
int
>::
const_iterator
find_first_bigger(
const
vector
<
int
> &
vec
,
const
string
&
s
)
{
            
return
find_if(
vec
.cbegin(),
vec
.cend(),
                        bind(check_size,
s
, placeholders::_1));
}
int
main()
{
            
vector
<
int
> vec = { 1, 2, 3, 4, 5, 6 };
            
string
s = {
"test"
};
            cout << *find_first_bigger(vec, s)<<endl;
//5,找到第一个比字符串“test“ 4 大的数.

            
return
0;

}

再探迭代器
除了为每个容器定义的迭代器之外,标准库在头文件iterator中还定义了额外几种迭代器:
插入迭代器:这些迭代器被绑定到一个容器上,可以来向容器插入元素。
流迭代器:这些迭代器被绑定到输入输出流上,可用来遍历所关联的IO流。
反向迭代器:这些迭代器向后面不是向前移动,除了forword_list之外的标准库容器都有反向迭代器。
移动迭代器:这些专用的迭代器不是拷贝其中的元素,而是移动它们。

插入迭代器


流迭代器


笔记:C++学习之旅---泛型算法的更多相关文章

  1. 【c++ Prime 学习笔记】第10章 泛型算法

    标准库未给容器添加大量功能,而是提供一组独立于容器的泛型算法 算法:它们实现了一些经典算法的公共接口 泛型:它们可用于不同类型的容器和不同类型的元素 利用这些算法可实现容器基本操作很难做到的事,例如查 ...

  2. C++ Primer 读书笔记:第11章 泛型算法

    第11章 泛型算法 1.概述 泛型算法依赖于迭代器,而不是依赖容器,需要指定作用的区间,即[开始,结束),表示的区间,如上所示 此外还需要元素是可比的,如果元素本身是不可比的,那么可以自己定义比较函数 ...

  3. 笔记-JavaWeb学习之旅7

    JavaScript基础 概念:一门客户端脚本语言,运行在客户端浏览器中,每一个浏览器都有JavaScript的解析引擎,是一个脚本语言,不需要编译,直接就可以被浏览器解析执行. JavaScript ...

  4. 笔记-JavaWeb学习之旅5

    CP30的演示 package cn.itcast.datasourcejdbc; import com.mchange.v2.c3p0.ComboPooledDataSource; import j ...

  5. 笔记-JavaWeb学习之旅19

    Redis:redis是一款高性能的NOSQL系列的非关系型数据库 NOSQL: Not Only SQL ,意即"不仅仅是SQL",是一项全新的数据库理念,泛指非关系型数据库 r ...

  6. 笔记-JavaWeb学习之旅18

    AJAX:ASynchronous JavaScript And XML 异步的JavaScript 和XML 异步和同步:客户端和服务器端相互通信的基础上 同步:客户端操作后必须等待服务器端的响应, ...

  7. 笔记-JavaWeb学习之旅17

    1.过滤选择器 首元素选择器:first 获得选择的元素中的第一个元素 尾元素选择器:last获得选择元素中的最后一个元素 非元素选择器:not(selector) 不包括指定内容的元素 偶数选择器: ...

  8. 笔记-JavaWeb学习之旅16

    增强对象的功能 动态代理:在内存中形成代理类 实现步骤: 代理对象和真实对象实现相同的接口 代理对象 = Proxy.newProxyInstance(); 使用代理对象调用真实对象的方法 增强方法 ...

  9. 笔记-JavaWeb学习之旅15

    Filter:过滤器 概念:当访问服务器的资源是,过滤器可以将请求拦截下来,完成一些特殊的功能 快速入门: 步骤: 定义一个类,实现接口Filter 复写方法 配置拦截路径 package com.d ...

  10. 笔记-JavaWeb学习之旅14

    JSTL:JavaServer Pages Tag Library JSP标准标签库 if标签 <%@ page import="java.util.ArrayList" % ...

随机推荐

  1. UG二次开发-CAM-执行方式

    以C#开发为例,通常先用[操作记录]功能录制关键代码,得到一个.cs文件. (1)可以直接使用[播放操作记录]的方式执行该.cs文件. (2)可以建立一个C#的类库工程,将上述.cs文件加载进去,添加 ...

  2. 2019之VLC3.071版本Ubuntu 18-win32-64为编译经验记录

    编译环境:1.win7+vmware15+Ubuntu 18 64bit虚拟系统(16也可以)2.gcc 7.4 (大于6即可)3.mingw-w64 5.3.0,及其相关联的x86-64的tool, ...

  3. Spring整合Redis学习笔记

    1 Spring-Data-Redis 1.1 Spring-Data-Redis简介   Spring-Data-Redis(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的 ...

  4. 三种遍历的方法(map和forEach的区别)

    一. for循环 arr[index]可以改变原数组 二. forEach方法 forEach方法的返回值是一个undefined: 2. 在循环体内改变item的值不会影响原数组,而是只在循环体内生 ...

  5. ssh原理及应用

    SSH原理与运用(一):远程登录 SSH原理与运用(一):远程登录 SSH原理与运用(二):远程操作与端口转发 SSH原理与运用(二):远程操作与端口转发 mitm应用: python开源三方库:ss ...

  6. 基本的dns命令

    打开cmd的方式 win+r 键 输入cmd       管理员方式运行    打开桌面  命令提示符 盘符切换 直接输入要切换的盘 查看当前目录下所有文件   dir 切换目录  cd  /d 跨盘 ...

  7. 手把手教你蜂鸟e203移植(以Nexys4DDR为例)

    准备工作:(网盘链接:) 1.蜂鸟e203的RTL源码: 2.一段分频代码: 3.顶层设计文件(system.v) 4.开发板文件: 5.Nexys4DDR电路图: 6.Nexys4DDR管脚约束模板 ...

  8. 如何规避MyBatis使用过程中带来的全表更新风险

    作者:京东零售 贾玉西 一.前言 程序员A: MyBatis用过吧? 程序员B: 用过 程序员A: 好巧,我也用过,那你遇到过什么风险没?比如全表数据被更新或者删除了. 程序员B: 咔,还没遇到过,这 ...

  9. Linux & 标准C语言学习 <DAY11>

    一.指针     1.什么是指针         指针是一种特殊的数据类型,使用指针可以定义指针变量,指针变量存储的是整形数据,该数据代表了内存的编号(地址),可以通过这个编号访问到对应的内存     ...

  10. 细节讲解并实操下: 去中心化社交协议 ---- Nostr

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. GitHub : https://github.com/af913337456/ 出版的书籍: <1.0-区块链DApp开发实战&g ...