zoukankan      html  css  js  c++  java
  • c++ primer 第五版第十章

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

    void test1001()
    {
        int ia[] = {1, 2, 2, 4, 3, 51, 2};
        int num = 2;
        vector<int> ivec(ia, ia+7);
        int result = count(ivec.begin(), ivec.end(), num);
        cout << result << endl;
    }
    

    10.02 重做上一题,但读取string序列存入list中。

    void test1002()
    {
        string sa[] = {"1", "a", "abc", "abc", "abc", "bc", "abc"};
        string str = "abc";
        list<string> slst(sa, sa+7);
        int result = count(slst.begin(), slst.end(), str);
        cout << result << endl;
    }
    

    10.03 用accumulate求一个vector中的元素之和。

    void test1003()
    {
        int ia[] = {1, 2, 2, 4, 3, 51, 2};
        vector<int> ivec(ia, ia+7);
    
        int sum = accumulate(ivec.begin(), ivec.end(), 0);
        cout << sum << endl;
    }
    

    10.04 假定v是一个vector, 那么调用accumulate(v.cbegin(), v.cend(), 0)有何错误(如果存在)?

    因为第三个参数是0,则编译器会认为其是一个int类型。最后的求和会损失精度。

    10.05 在本节对名册(roster)调用equal的例子中,如果两个名册中保存的都是c风格字符串而不是string,会发生什么?

    c风格字符串有begin(), end()函数吗?不能使用equal,可以使用strcmp。

    10.06 编写程序,使用fill_n将一个序列中的int都设置为0。

    void test1006()
    {
        vector<int> ivec(10);
        for (int i = 0; i < 10; i++) {
            ivec[i] = i+1;
        }
    
        fill_n(ivec.begin(), ivec.size(), 0);
    }
    

    10.07 下面程序是否有错误?如果有,请改正。

    // a
    vector<int> vec; list<int> lst; int i;
    while (cin >> i)
        lst.push_back(i);
    copy(lst.cbegin(), lst.cend(), vec.begin());
    // 有错误,vec的大小为0,直接将lst复制到vec,将会发生不可预料的错误。
    在copy前加上:vec.resize(lst.size());
    // b
    vector<int> vec;
    vec.reserve(10);		// reserve是改变容器容量的,并不能改变容器大小。应改为resize。
    fill_n(vec.begin(), 10, 0);
    

    10.08 本节提到过,标准库算法不会改变他们所操作的容器的大小。为什么使用back_inserter不会使这一断言失效?

    通过插入迭代器来插入元素,使用的是迭代器,而不是算法插入。

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

    void elimDups(vector<string>& words)
    {
        sort(words.begin(), words.end());   // 按字典序重排words
    
        for (auto i : words) {
            cout << i << " ";		// fox jumps over quick red red slow the the turtle
        }
        cout << endl;
        auto end_unique = unique(words.begin(), words.end());       // 重排,使每个单词只出现一次,指向不重复区域之后的迭代器。
        for (auto i : words) {
            cout << i << " ";		// fox jumps over quick red slow the turtle the red
        }
        cout << endl;
        words.erase(end_unique, words.end());
        for (auto i : words) {
            cout << i << " ";		// fox jumps over quick red slow the turtle
        }
        cout << endl;
    }
    

    10.10 你认为算法不改变容器大小的原因是什么?

    标准库算法对迭代器而不是容器进行操作,因此,算法不能(直接)添加或删除元素。

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

    void test1009()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"};
        elimDups(svec);
        printVec(svec);		// fox jumps over quick red slow the turtle
        // use isShorter
        sort(svec.begin(), svec.end(), isShorter);
        printVec(svec);		// fox red the over slow jumps quick turtle
        
        // use stable_sort
        stable_sort(svec.begin(), svec.end(), isShorter);
        printVec(svec);		// fox red the over slow jumps quick turtle
    }
    

    10.12 编写名为compareIsbn的函数,比较两个Sales_data对象的isbn()成员。使用这个函数排序一个保存Sales_data对象的vector。

    bool compareIsbn(const Sales_data& sale1, const Sales_data& sale2)
    {
        return sale1.isbn().size() > sale2.isbn().size();
    }
    void test1012()
    {
        vector<Sales_data> sale_vec;
        string bookNo = "";
        for (int i = 0; i < 5; i++) {
            bookNo += "s";
            cout << bookNo << endl;
            sale_vec.push_back(Sales_data(bookNo));
        }
        for (auto i : sale_vec) {
            print(cout, i);
        }
        sort(sale_vec.begin(), sale_vec.end(), compareIsbn);
        for (auto i : sale_vec) {
            print(cout, i);
        }
    }
    

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

    bool isStrLongThan5(string& str)
    {
        return str.size() >= 5;
    }
    
    void test1013()
    {
        vector<string> svec = {"hello", "world", "bin", "is", "the", "banana"};
        auto it = partition(svec.begin(), svec.end(), isStrLongThan5);
        printVec(svec);
        while (-- it != (svec.begin()-1)) {
            cout << *it << " ";
        }
    }
    

    10.14 编写一个lambda,接受两个int,返回它们的和。

    auto sum = [](const int a, const int b) { return a+b; }
    

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

    auto sum = [a](const int b) { return a+b; }
    

    10.16 使用lambda编写你自己版本的biggies。

    void biggies(vector<string>& words, size_t sz)
    {
        elimDups(words);
        printVec(words);
        stable_sort(words.begin(), words.end(), [](const string& str1, const string& str2){ return (str1.size()>=str2.size());});
        find_if(words.begin(), words.end(), [sz](const string& str){ return str.size()>sz;});
        printVec(words);
    }
    
    void test1016()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle"};
        biggies(svec, 4);
    }
    

    10.17 重新10.12的程序,在对sort的调用中使用lambda来代替函数compareIsbn。

    sort(sale_vec.begin(), sale_vec.end(), [](const Sales_data& sale1, const Sales_data& sale2) { return sale1.isbn().size() > sale2.isbn().size(); });
    // 将12题中的sort一行改为上述语句即可。
    

    10.18 重写biggies,用partition代替find_if。我们在10.13中介绍了partition算法。

    partition(words.begin(), words.end(), [sz](const string& str){ return str.size()>sz;});
    // 将16题中的find_if一句改为上述数据即可。
    

    10.19 用stable_partition重写前一题的程序,与stable_sort类似,在划分后的序列中维持原有元素的顺序。

    stable_partition(words.begin(), words.end(), [sz](const string& str){ return str.size()>sz;});
    // 将上题中的partition一行改为上述语句。
    

    10.20 标准库定义了一个名为count_if的算法。类似find_if,此函数接受一对迭代器,表示一个输入范围,还接受一个谓词,会对输入范围中每个元素执行。count_if返回一个计数值,表示谓词有多少次为真。使用count_if重写我们程序中统计有多少单词长度超过6的部分。

    void test1020()
    {
        int sz = 6;
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red road", "turtle"};
        int cnt = count_if(svec.begin(), svec.end(), [sz](const string& str){ return str.size()>sz;});
    
        cout << cnt << endl;
    }
    

    10.21 编写一个lambda,捕获一个局部int变量,并递减变量值,直至它变为0.一旦变量变为0,再调用lambda应该不再递减变量.lambda应该返回一个bool值,指出捕获的变量是否为0.

    void test1021()
    {
        int val = 5;
        auto f = [&val]()->bool {
            if (0 == val) {
                return true;
            } else {
                -- val;
                return false;
            }
        };
        while (!f()) {
            cout << val << endl;
        }
    }
    

    10.22 重写统计长度小于等于6的单词数量的程序,使用函数代替lambda.

    bool isStrShorterThan6(string& str)
    {
        return str.size() < 6;
    }
    void test1022()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red road", "turtle"};
        int cnt = count_if(svec.begin(), svec.end(), isStrShorterThan6);
        cout << cnt << endl;
    }
    

    10.23 bind接受几个参数?

    auto newCallable = bind(callable, arg_list);

    其中,arg_list是一个用逗号分隔的参数列表,对应给callable的参数。当我们调用newCallable时,实际会调用callable。

    arg_list中的参数可能会包含形如_n的名字,其中n是一个整数。这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数位置。

    10.24 给定一个string, 使用bind和check_size在一个int的vector中查找第一个大于string长度的值.

    using namespace placeholders;
    bool check_size(string& str, size_t sz)
    {
        return str.size()>sz;
    }
    void test1024()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red road", "turtle"};
        auto iter = find_if(svec.begin(), svec.end(), bind(check_size, _1, 6));
        cout << *iter << endl;
    }
    

    10.25 在10.3.2节的练习中,编写了一个使用partition的biggies版本.使用check_size和bind重写此函数.

    void biggies_25(vector<string>& words, size_t sz)
    {
        printVec(words);
        auto iter = partition(words.begin(), words.end(), bind(check_size, _1, 6));
        printVec(words);
    }
    
    void test1025()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "congratulate", "turtle"};
        biggies_25(svec, 5);
    }
    

    10.26 解释三种插入迭代器的不同之处。

    三种迭代器的区别在于元素插入的位置:

    1. back_inserter:创建一个使用push_back的迭代器。
    2. front_insert:创建一个使用push_front的迭代器。
    3. inserter:创建一个使用insert的迭代器。此函数接受第二个参数,元素将被插入到给定迭代器所表示的元素之前。

    10.27 处理unique之外,标准库还定义了名为unique_copy的函数,它接受第三个迭代器,表示拷贝不重复元素的目的位置。编写一个程序,使用unique_copy将一个vector中不重复的元素拷贝到一个初始化为空的list中。

    void test1027()
    {
        vector<string> svec = {"the", "quick", "red", "fox", "jumps", "over", "the", "slow", "congratulate", "turtle"};
        list<string> slst(15);		// 注意list要分配空间,否则没有地方拷贝,程序core掉。
    
        unique_copy(svec.begin(), svec.end(), slst.begin());	
        for (auto i : slst) {
            cout << i << " ";
        }
        cout << endl;
    }
    

    10.28 一个vector中保存1到9,将其拷贝到三个其他容器中。分别使用inserter, back_inserter和front_inserter将元素添加到三个容器中。对每种inserter,估计输出序列是怎样的,运行程序验证你的估计是否正确。

    void test1028()
    {
        vector<int> ivec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        vector<int> ivec_dst1;
        list<int> ivec_dst2;		// 注意vector没有push_front方法,因此不能用front_inserter.list有该方法。
        vector<int> ivec_dst3;
    
        auto iter1 = ivec_dst1.begin();
    
        copy(ivec.begin(), ivec.end(), inserter(ivec_dst1, iter1));
        copy(ivec.cbegin(), ivec.cend(), front_inserter(ivec_dst2));
        copy(ivec.cbegin(), ivec.cend(), back_inserter(ivec_dst3));
    
        printContainer(ivec_dst1);
        printContainer(ivec_dst2);
        printContainer(ivec_dst3);
    }
    

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

    void readByFile(vector<string>& svec, string fileName)
    {
        ifstream in(fileName);
        istream_iterator<string> in_iter(in);
        istream_iterator<string> eof;
    
        while (in_iter != eof) {
            svec.push_back(*in_iter++);
        }
    
        printContainer(svec);
    }
    
    void test1029()
    {
        string fileName = "C:/Users/tutu/Documents/code/cpp_primer/ch10/string.txt";
        vector<string> svec;
    
        readByFile(svec, fileName);
    }
    

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

    void test1030()
    {
        istream_iterator<int> in_iter(cin);
        istream_iterator<int> eof;
        vector<int> ivec;
        ostream_iterator<int> out_iter(cout, " ");
    
        while (in_iter != eof) {
            ivec.push_back(*in_iter++);
        }
        sort(ivec.begin(), ivec.end());
        copy(ivec.begin(), ivec.end(), out_iter);
        cout << endl;
    }
    

    10.31 修改前一题的程序,使其只打印不重复的元素。你的程序应使用unique_copy。

    // 将上题中的copy一行改为:
    unique_copy(ivec.begin(), ivec.end(), out_iter);
    

    10.32 重写1.6节的书店程序,使用一个vector保存交易记录,使用不同算法完成处理。使用sort和10.3.1节中的compareIsbn函数来排序交易记录,然后使用find和accumulate求和。

    void test1031()
    {
        Sales_item total;
        istream_iterator<Sales_item> in_iter(cin);
        istream_iterator<Sales_item> eof;
        vector<Sales_item> sale_vec;
    
        while (in_iter != eof) {
            sale_vec.push_back(*in_iter++);
        }
    
        sort(sale_vec.begin(), sale_vec.end(), compareIsbn);
        Sales_item sale_sum;
        for (auto beg = sale_vec.cbegin(), end = beg; beg != sale_vec.cend(); beg = end) {
            end = find_if(beg, sale_vec.cend(), [beg](const Sales_item &item){ return item.isbn() != beg->isbn(); });
            cout << accumulate(beg, end, Sales_item(beg->isbn())) << endl;
        }
    }
    // Sales_item类中需要重载"<<" ">>" "+" "+="等符号,才能支持accumulate函数的运算。
    

    10.33 编写程序,接受三个参数:一个输入文件和两个输出文件的文件名。输入文件保存的应该是整数。使用istream_iterator读取输入文件。使用ostream_iterator将奇数写入第一个输出文件,每个值之后都跟一个空格。将偶数写入第二个输出文件,每个值都独占一行。

    void readIntByFile(string& in_file, string& out_file_odd, string& out_file_even)
    {
        ifstream in(in_file);
        ofstream out_odd(out_file_odd);
        ofstream out_even(out_file_even);
        istream_iterator<int> in_iter(in), eof;
        ostream_iterator<int> out_iter_odd(out_odd, " "), out_iter_even(out_even, "
    ");
    
        std::for_each(in_iter, eof, [&out_iter_odd, &out_iter_even](const int i) {
                 (i%2 ? out_iter_odd : out_iter_even)++ = i;
                 });
    }
    
    void test1033()
    {
        string inFileName = "C:/Users/tutu/Documents/code/cpp_primer/ch10/int.txt";
        string outFileOdd = "C:/Users/tutu/Documents/code/cpp_primer/ch10/odd.txt";
        string outFileEven = "C:/Users/tutu/Documents/code/cpp_primer/ch10/even.txt";
    
        readIntByFile(inFileName, outFileOdd, outFileEven);
    }
    

    10.34 使用reverse_iterator逆序打印一个vector。

    void test1034()
    {
        vector<int> ivec = {0, 1, 2, 3, 4, 5, 6};
    
        for (auto riter = ivec.crbegin(); riter != ivec.crend(); ++ riter) {
            cout << *riter << " ";
        }
        cout << endl;
    }
    

    10.35 使用普通迭代器逆序打印一个vector。

        auto iter = ivec.cend();
        while (iter != ivec.cbegin()) {
            cout << *--iter << " ";
        }
        cout << endl;
    

    10.36 使用find在一个int的list中查找最后一个值为0的元素。

    void test1035()
    {
        list<int> ilst = {0, 1, 2, 3, 4, 5, 6, 0, 1, 3};
        auto find_iter = find (ilst.crbegin(), ilst.crend(), 0);
        int dis = distance(find_iter, ilst.crend());
        cout << dis << endl;
    }
    

    10.37 给定一个包含10个元素的vector,将位置3到7之间的元素按逆序拷贝到一个list中。

        vector<int> ivec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        list<int> dst_lst(10);
        copy(ivec.cbegin()+3, ivec.cbegin()+8, dst_lst.rbegin());
        for (auto i : dst_lst) {
            cout << i << " ";
        }
        cout << endl;
    

    10.38 列出5个迭代器类别,以及每类迭代器所支持的操作。

    1. 输入迭代器:只读,不写;单遍扫描,只能递增。支持==、!=、++、*、->
    2. 输出迭代器:只写,不读;单遍扫描,只能递增。支持++、*
    3. 前向迭代器:可读写,多边扫描,只能递增。支持输入输出迭代器的所有操作。
    4. 双向迭代器:可读写,多遍扫描,可递增递减。除支持前向迭代器的操作外,还支持--。
    5. 随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算。除支持双向操作外,还支持<、<=、>、>=、+、+=、-、-=、迭代器的减法运算符(-)、下标运算符(iter[n], *(iter[n]) )。

    10.39 list上的迭代器属于哪类?vector呢?

    list的迭代器属于双向迭代器。

    vector属于随机访问迭代器。

    10.40 你认为copy要求哪类迭代器?reverse和unique呢?

    copy前两个参数要求输入迭代器,最后一个参数要求输出迭代器。

    reverse要求双向迭代器。

    unique要求前向迭代器。

    10.41 仅根据算法和参数的名字,描述下面每个标准库算法执行什么操作:

    replace(beg, end, old_val, new_val);
    replace_if(beg, end, pred, new_val);
    replace_copy(beg, end, dest, old_val, new_val);
    replace_copy_if(beg, end, dest, pred, new_val);
    

    10.42 使用list代替vector重新实现10.2.3节中的去除重复单词的程序。

    void test1042()
    {
        list<int> ilst = {0, 1, 1,2, 3, 4, 5, 6, 0, 1, 3};
        ilst.sort();
        ilst.unique();
    
        for (auto i : ilst) {
            cout << i << " ";
        }
        cout << endl;
    }
    
  • 相关阅读:
    小程序踩坑(三)-上拉加载和下拉刷新篇
    小程序踩坑(二)
    小程序入门(一)
    移动端那些事(一)
    css3写单选框,复选框
    websockect入门(一)
    一个简单的blog系统(十六) 增加日志功能
    一个简单的blog系统(十四) 增加用户头像
    一个简单的blog系统(十三) 增加404页面
    一个简单的blog系统(十二) 增加友情链接页面
  • 原文地址:https://www.cnblogs.com/songshuguiyu/p/9547238.html
Copyright © 2011-2022 走看看