第10章 泛型算法

大多数算法定义在algorithm中。标准库还在头文件numeric中定义了一组数值泛型算法

练习10.1:头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数。count返回给定值在序列中出现的次数。编写程序,读取int序列存入vector中,打印有多少个元素的值等于给定值,

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int main()
{
    vector<int> nums = {123,456,789,123,456,789,1};
    cout << count(nums.cbegin(), nums.cend(), 123) << endl;

    return 0;
}

练习10.3:用accumulate求一个vector<int>中的元素之和

#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

int main()
{
    vector<int> nums = {1,2,3,4,5,6};
    cout << accumulate(nums.cbegin(), nums.cend(), 0);
    return 0;
}

练习10.9:实现你自己的elimDups。测试你的程序,分别在读取输入后、调用unique后以及调用erase后打印vector的内容。

void elimDups(vector<string> & words)
{
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

练习10.11:编写程序,使用stable_sort和isShorter将传递给你的elimDups版本的vector排序。打印vector的内容,验证你程序的正确性

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
bool isShorter(const string &s1, const string &s2)
{
    return s1.size() < s2.size();
}
void elimDups(vector<string> & words);
int main()
{
    vector<string> words = {"the", "quick", "red", "fox", "jumps", "over",
                            "the", "slow", "red", "turtle"};
    elimDups(words);
    stable_sort(words.begin(), words.end(), isShorter);
    for (auto i : words)
        cout << i << " ";
    
    return 0;
}

void elimDups(vector<string> & words)
{
    sort(words.begin(), words.end());
    auto end_unique = unique(words.begin(), words.end());
    words.erase(end_unique, words.end());
}

练习10.13:标准库定义了名为partition的算法,它接受一个谓词,对容器内容进行划分,使得谓词为true的值会排在容器的前半部分,而未日次false的值会在后半部分。算法返回一个迭代器指向最后一个使谓词位true的元素之后的位置。编写一个函数,接受string,返回bool,指出string是否有5个或更多字符。使用此函数划分words打印长度大于等于5的元素,

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

using namespace std;

bool compareWords(const string &);

int main()
{
    vector<string> words = {"the", "quick", "red", "fox", "jumps", "over",
                            "the", "slow", "red", "turtle"};
    auto end = partition(words.begin(), words.end(), compareWords);
    for (auto i = words.begin(); i != end; ++i)
    {
        cout << *i << " ";
    }

    return 0;
}

bool compareWords(const string & words)
{
    return words.size() > 4;
}

lambda

lambda表达式形式:
[capture list] (parameter list) -> return type { function body}

  • 捕获列表只用于局部非静态变量。
  • 可以直接使用局部静态变量和外部变量

练习10.14:编写一个lambda,接受两个int,返回他们的和。

#include <iostream>

using namespace std;
int main()
{
    int a = 5, b = 4;
    auto f = [](const int a, const int b) {return a + b;};
    cout << f(a, b) << endl;
}

练习10.15:编写一个lambda,捕获它所在函数的int,并接受一个int参数。lambda应该返回捕获的int和int参数的和。

#include <iostream>

using namespace std;
int main()
{
    int a = 5, b = 4;
    auto f = [a](const int b) {return a + b;};
    cout << f(b) << endl;
}

从写biggies用partition代替find_if

void biggies(vector<string> &words, vector<string>::size_type sz)
{
    elimDups(words);
    stable_sort(words.begin(), words.end(),
                        [](const string &a, const string &b)
                            { return a.size() < b.size();});
    auto wz = partition(words.begin(), words.end(),
                            [sz](string &a)
                                { return a.size() < sz;});
    for_each( wz, words.end(),
                [](const string &a)
                    {cout << a << " ";});
    cout << endl;
}

在创建lambda的时候捕获列表就保存了捕获的值
修改捕获列表的值必须使用mutable
auto f = [&a] () mutable {return ++a;};
返回其他类型使用尾置返回类型

可以使用bind代替lambda
引用 ref bind(print, ref(os), _1, ' ')
placeholders命名空间
using namespace std::placeholders;

练习10.22:重写统计长度小于等于5的单词数量的程序。使用函数代替lambda;

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <functional>

using namespace std;
using namespace std::placeholders;

void biggies(vector<string> &words, vector<string>::size_type sz);
void elimDups(vector<string> &words);
bool check6(const string &a, string::size_type sz);  //bind

int main()
{
    vector<string> words = {"the", "quick", "red", "fox", "jumps", "over",
                            "the", "slow", "red", "turtle"};
    biggies(words, 5);
}

void elimDups(vector<string> &words)
{
    sort(words.begin(), words.end());
    auto no_unique = unique(words.begin(), words.end());
    words.erase(no_unique, words.end());
}

void biggies(vector<string> &words, vector<string>::size_type sz)
{
    elimDups(words);
    stable_sort(words.begin(), words.end(),
                        [](const string &a, const string &b)
                            { return a.size() < b.size();});
    auto wz = find_if(words.begin(), words.end(), 
                        bind(check6, _1, sz));
    for_each(words.begin(), wz,
                [](const string &a)
                    {cout << a << " ";});
    cout << endl;
}

bool check6(const string &a, string::size_type sz)
{
    return a.size() > sz;
}

练习10.23:bind接受几个参数?
auto newCallable = bind(callable, arg_list);


image.png

练习10.26:解释三种插入迭代器的不同之处

  • back_inserter:创建使用push_back的迭代器
  • front_inserter创建一个使用push_front的迭代器
  • inserter:创建一个使用insert的迭代器。此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。

练习10.27:使用unique_copy函数将不重复的字母copy到一个初始化为空的list中

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <list>

using namespace std;

int main()
{
    vector<string> words = {"the", "quick", "red", "fox", "jumps", "over",
                        "the", "slow", "red", "turtle"};
    list<string> wwww;
    sort(words.begin(), words.end());
    unique_copy(words.cbegin(), words.cend(), inserter(wwww, wwww.begin()));
    for (auto i : words)
        cout << i << " ";
    cout << endl;
    for (auto i : wwww)
        cout << i << " ";
    cout << endl;

    return 0;
}

练习10.28:一个vector中保存1-9用三种迭代器copy到三种不同的容器


练习10.29:编写程序,使用流迭代器读取一个文本文件,存入一个vector中的string里

#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    ifstream in("1.txt");
    istream_iterator<string> str_it(in);
    istream_iterator<string> eof;
    vector<string> str(str_it, eof);

    ostream_iterator<string> out_iter(cout, " ");
    copy(str.cbegin(), str.cend(), out_iter);
    cout << endl;

    return 0;
}

练习10.30:使用流迭代器、sort和copy从标准输入读取一个整数序列,将其排序,并将结构写到标准输出

#include <iostream>
#include <vector>
#include <iterator>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    istream_iterator<int> in_iter(cin);
    istream_iterator<int> eof;
    vector<int> nums(in_iter, eof);
    sort(nums.begin(), nums.end());
    ostream_iterator<int> out_iter(cout, " ");
    copy(nums.cbegin(), nums.cend(), out_iter);

    return 0;
}

练习10.34:使用reverse_iterator逆序打印一个vector

#include <iostream>
#include <vector>
#include <string>
#include <iterator>

using namespace std;
int main()
{
    vector<int> vec = {1,2,3,4,5,6,7,8};
    for (auto r_iter = vec.crbegin(); 
                r_iter != vec.crend();
                ++r_iter)
        cout << *r_iter << endl;
    return 0;
}

练习10.37:给定一个包含10个元素的vector,将3-7之间的元素逆序拷贝到list中

#include <iostream>
#include <list>
#include <vector>

using namespace std;
int main()
{
    vector<int> num = {1,2,3,4,5,6,7,8,9,0};
    list<int> nums(num.crbegin() + 3, num.crend() - 2);
    for (auto i : nums)
        cout << i << " ";
    cout << endl;

    return 0;
}

练习10.38:列出5个迭代器类别,以及每类迭代器所支持的操作。
输入迭代器:只读,不写;单遍扫描,只能递增
输出迭代器:只写,不读:单遍扫描,只能递增
前向迭代器:可读写;多遍扫描,只能递增
双向迭代器:可读写;多遍扫描,可递增递减
随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容

  • 10.1概述 迭代器算法不会依赖容器,体现其泛型,但算法会依赖元素类型的操作,如排序算法sort默认使用<运算符,...
    夜风_3b8d阅读 275评论 0 0
  • 10.1 概述 范型算法:实现了一些经典算法的公共接口,可用于不同类型的元素、多种类型的容器、其他类型序列。 迭代...
    咸鱼翻身ing阅读 197评论 0 0
  • 10.1 概述 #include //大部分算法定义 #include <numeric> //数值泛型算法 ...
    龙遁流阅读 577评论 0 1
  • #1.概述 #2.初始泛型算法只读算法写容器元素的算法重排容器元素的算法 #3.定制操作向算法传递函数lambda...
    MrDecoder阅读 694评论 0 0
  • 标准库容器定义的操作集合惊人的小。标准库并未给每个容器添加大量功能,而是提供了一组算法,这些算法中的大多数都独立于...
    梦中睡觉的巴子阅读 575评论 0 0