zoukankan      html  css  js  c++  java
  • C++ Primer 5th 第10章 泛型算法

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

    #include <iostream>
    #include <algorithm>
    #include <vector>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};
    
        std::cout << count(v.begin(), v.end(), 4) << std::endl;
        return 0;
    }

    练习10.2:重做上一题,但读取string序列存入 list 中。

    #include <iostream>
    #include <algorithm>
    #include <list>
    
    int main()
    {
        std::list<std::string> v = {"af", "fe", "fea", "ers", "ht", "tq", "bs", "et"};
        std::cout << count(v.begin(), v.end(), "ab") << std::endl;
    
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};
        std::cout << std::accumulate(v.begin(), v.end(), 0) << std::endl;
    
        return 0;
    }

    练习10.4:假定v是一个vector<double>,那么调用 accumulate(v.cbegin(),v.cend(),0) 有何错误(如果存在的话)?

    由于类型不同,隐式转换时会导致丢失精度,最终结果与实际结果有偏差。


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

    练习10.6:编写程序,使用fill_n将一个序列中的 int 值都设置为 0。

    #include <iostream>
    #include <algorithm>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};
        fill_n(v.begin(), v.size(), 0);
        return 0;
    }

    练习10.7:下面程序是否有错误?如果有,请改正:

    (a) vector<int> vec; list<int> lst; int i;
        while (cin >> i)
            lst.push_back(i);
        copy(lst.cbegin(), lst.cend(), vec.begin());
    (b) vector<int> vec;
        vec.reserve(10);
        fill_n(vec.begin(), 10, 0);

    (a)vec是空vector,不可以使用copy
    (b)vec也是空vector,虽然底层内存上是正确的,但逻辑上错误。

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

    因为back_inserter不属于标准库泛型算法,它是在头文件iterator中定义的,而泛型算法是在algorithm中定义的。

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

    #include <iostream>
    #include <algorithm>
    
    using std::cout;
    using std::endl;
    
    void eliminate_duplicates(std::vector<std::string> &v)
    {
        std::sort(v.begin(), v.end());
        for (auto i : v)
        {
            cout << i << "  ";
        }
        cout << endl;
    
        auto end_unique = std::unique(v.begin(), v.end());
        for (auto i : v)
        {
            cout << i << "  ";
        }
        cout << endl;
    
        v.erase(end_unique, v.end());
        for (auto i : v)
        {
            cout << i << "  ";
        }
        cout << endl;
    
    }
    
    int main()
    {
        std::vector<std::string> v = {"abc", "abc", "efg", "hij", "klmn", "opq", "xyz", "klmn"};
        eliminate_duplicates(v);
        return 0;
    }


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

    算法不改变容器将使用户不需要顾忌容器的迭代器失效问题。

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

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    //using namespace std;
    
    void elimDups(std::vector<std::string>& words)
    {
        std::sort(words.begin(), words.end());
        auto unique_end = unique(words.begin(), words.end());
        words.erase(unique_end, words.end());
    }
    
    bool isShorter(const std::string& i1, const std::string& i2)
    {
        return i1.size() < i2.size();
    }
    
    int main()
    {
        std::vector<std::string> word = {"1", "2", "5", "3", "13", "3", "2", "3", "32", "1"};
        elimDups(word);
        stable_sort(word.begin(), word.end(), isShorter);
        for (auto one : word)
        {
            std::cout << one << '	';
        }
        std::cout << std::endl;
        return 0;
    }

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

    bool compareIsbn(const Sales_data &sd1, const Sales_data &sd2)
    {
        return sd1.isbn().size() < sd2.isbn().size();
    }
    
    std::sort(v.begin(), v.end(), compareIsbn);

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

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    //using namespace std;
    
    bool morethan5(const std::string& s)
    {
        return s.size() < 5;
    }
    
    int main()
    {
        std::vector<std::string> words = {"hello", "one", "two", "three", "seven", "eleven"};
        partition(words.begin(), words.end(), morethan5);
        for (auto one : words)
        {
            std::cout << one << ' ';
        }
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    
    int main(int argc, char const *argv[])
    {
        auto f = [](int i, int j) {return i + j;};
        std::cout << f(4, 7) << std::endl;
        return 0;
    }

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

    #include <iostream>
    
    int main(int argc, char const *argv[])
    {
        int i = 9;
        auto f = [i](int j) {return i + j;};
        std::cout << f(7) << std::endl;
        return 0;
    }


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

    练习10.17:重写10.3.1节练习10.12(第345页)的程序,在对sort的调用中使用 lambda 来代替函数 compareIsbn。

    std::sort(v.begin(), v.end(), [](const Sales_data &sd1, const Sales_data &sd2) 
    {
    return sd1.isbn().size() < sd2.isbn().size();
    });

    练习10.18:重写 biggies,用 partition 代替 find_if。我们在10.3.1节练习10.13(第345页)中介绍了 partition 算法。

    #include <iostream>
    #include <algorithm>
    
    void elimDups(std::vector<std::string> &v)
    {
        std::sort(v.begin(), v.end());
        auto end = std::unique(v.begin(), v.end());
        v.erase(end, v.end());
    }
    
    void biggies(std::vector<std::string> &words, std::size_t sz)
    {
        elimDups(words);
        stable_sort(words.begin(), words.end(), [](const std::string & a, const std::string & b)    { return a.size() < b.size();});
        auto wc = partition(words.begin(), words.end(), [sz](const std::string & s)  { return s.size() < sz; });
        auto count = words.end() - wc;
        std::cout << count << " " << "word(s)"
                  << " of length " << sz << " or longer" << std::endl;
        for_each(wc, words.end(),  [](const std::string & s) {std::cout << s << " ";});
        std::cout << std::endl;
    }
    
    int main()
    {
        std::vector<std::string> v = {"abc", "abc", "efg", "hij", "klmn", "opq", "xyz", "klmn"};
        biggies(v,4);
        return 0;
    }


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

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    void elimDups(std::vector<std::string> &v)
    {
        std::sort(v.begin(), v.end());
        auto end = std::unique(v.begin(), v.end());
        v.erase(end, v.end());
    }
    
    void biggies(std::vector<std::string> &words, std::size_t sz)
    {
        elimDups(words);
        auto wc = stable_partition(words.begin(), words.end(), [sz](const std::string & s) {return s.size() < sz;});
        auto count = words.end() - wc;
        std::cout << count << " " << "word(s)"
                  << " of length " << sz << " or longer" << std::endl;
        for_each(wc, words.end(),  [](const std::string & s) {std::cout << s << " ";});
        std::cout << std::endl;
    }
    
    int main()
    {
        std::vector<std::string> v = {"abc", "abc", "efg", "hij", "klmn", "opq", "xyz", "klmn"};
        biggies(v, 4);
        return 0;
    }


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

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    int main()
    {
        std::vector<std::string> v = {"abc", "hello", "I think", "I am", "alphabet"};
        std::cout << count_if(v.begin(), v.end(), [](const std::string & s1) {return s1.size() > 6;});
        return 0;
    }

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

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    int main()
    {
        int i = 99;
        auto lambda = [&i] ()mutable -> bool
        {    if (i != 0)
            {
                for (; i != 0; --i)
                {
                    continue;
                }
                return true;
            }
            return false;
    
        };
        lambda();
        std::cout << i << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <vector>
    #include <functional>
    #include <algorithm>
    
    bool f(const std::string s, std::size_t size)
    {
        return s.size() <= size;
    }
    
    int main()
    {
        std::vector<std::string> v = {"abc", "hello", "I think", "I am", "alphabet"};
        std::cout << count_if(v.begin(), v.end(), bind(f, std::placeholders::_1, 6));
        return 0;
    }


    练习10.23:bind 接受几个参数?

    没有限制


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

    #include <iostream>
    #include <vector>
    #include <functional>
    #include <algorithm>
    
    bool check_size(const std::string s, std::size_t size)
    {
        return s.size() < size;
    }
    
    int main()
    {
        std::string s;
        std::cin >> s;
        std::vector<int> v = {1, 2, 3, 4, 5};
        for (auto i : v)
        {
            auto f = bind(check_size, s, std::placeholders::_1);
            if ((f(i)))
            {
                std::cout << "finded.the element is " << i << std::endl;
    
                break;
            }
        }
        return 0;
    }

    练习10.25:在10.3.2节(第349页)的练习中,编写了一个使用partition 的biggies版本。使用 check_size 和 bind 重写此函数。

    #include <iostream>
    #include <algorithm>
    #include <functional>
    
    void elimDups(std::vector<std::string> &v)
    {
        std::sort(v.begin(), v.end());
        auto end = std::unique(v.begin(), v.end());
        v.erase(end, v.end());
    }
    
    bool f(const std::string& s, std::size_t sz)
    {
        return s.size() < sz;
    }
    
    void biggies(std::vector<std::string> &words, std::size_t sz)
    {
        elimDups(words);
        stable_sort(words.begin(), words.end(), [](const std::string & a, const std::string & b)
        {
            return a.size() < b.size();
        });
        auto wc = partition(words.begin(), words.end(), bind(f, std::placeholders::_1, sz) );
        auto count = words.end() - wc;
        std::cout << count << " " << "word(s)"
                  << " of length " << sz << " or longer" << std::endl;
        for_each(wc, words.end(),  [](const std::string & s) {std::cout << s << " ";});
        std::cout << std::endl;
    }
    
    int main()
    {
        std::vector<std::string> v = {"abc", "abc", "efg", "hij", "klmn", "opq", "xyz", "klmn"};
        biggies(v, 4);
        return 0;
    }

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

    back_inserter尾部插入,要求push_back操作
    front_inserter首部插入,要求front_inserter操作
    inserter 插入到指定位置


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

    #include <iostream>
    #include <list>
    #include <algorithm>
    
    int main()
    {
        std::vector<int> v = {1, 2, 2, 3, 3, 4, 5, 6, 7, 7};
        std::list<int> lst;
        unique_copy(v.begin(), v.end(), back_inserter(lst));
        for (auto i : lst)
        {
            std::cout << i << "  ";
        }
        std::cout << std::endl;
        return 0;
    }


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

    #include <algorithm>
    #include <iostream>
    #include <deque>
    #include <list>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        std::deque<int> v1, v2, v3;
        copy(v.begin(), v.end(), back_inserter(v1));
        copy(v.begin(), v.end(), front_inserter(v2));
        copy(v.begin(), v.end(), back_inserter(v3));
        std::cout << "v1  " << "v2  " << "v3" << std::endl;
        for (int i = 0; i != 9; ++i)
        {
            std::cout << v1[i] << "   " << v2[i] << "   " << v3[i] << std::endl;
        }
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <fstream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    #include <string>
    
    int main()
    {
        std::ifstream file_in("nmap.txt");
        if (file_in)
        {
            std::istream_iterator<std::string> in_it{file_in};
            std::istream_iterator<std::string> in_end;
            std::vector<std::string> v;
            std::copy(in_it, in_end, back_inserter(v));
            for (auto i : v)
            {
                std::cout << i << " ";
            }
        }
        else
        {
            std::cout << "file open failed.";
        }
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    int main()
    {
    
        std::istream_iterator<int> in_it{std::cin};
        std::istream_iterator<int> in_end;
    
        std::vector<int> v;
        std::copy(in_it, in_end, back_inserter(v));
        std::sort(v.begin(), v.end());
    
        std::ostream_iterator<int> out_it{std::cout, " "};
        std::copy(v.begin(), v.end(), *out_it++);
    
        std::cout << std::endl;
        return 0;
    }

    练习10.31:修改前一题的程序,使其只打印不重复的元素。你的程序应该使用 unique_copy(参见10.4.1节,第359页)。

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    int main()
    {
        std::istream_iterator<int> in_it{std::cin};
        std::istream_iterator<int> in_end;
    
        std::vector<int> v;
        std::copy(in_it, in_end, back_inserter(v));
        std::sort(v.begin(), v.end());
    
        std::ostream_iterator<int> out_it{std::cout, " "};
        std::unique_copy(v.begin(), v.end(), *out_it++);
    
        std::cout << std::endl;
        return 0;
    }

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


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

    #include <iostream>
    #include <fstream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    int main()
    {
        std::ifstream file_in{"file_in"};
        std::ofstream file_out1{"file_out1"}, file_out2{"file_out2"};
        if (!file_in || !file_out1 || !file_out2)
        {
            std::cout << "file open failed." << std::endl;
            return -1;
        }
        //in
        std::istream_iterator<int> in_it{file_in}, in_end;
    
        //out
        std::ostream_iterator<int> out_it1{file_out1, " "};
        std::ostream_iterator<int> out_it2{file_out2, " "};
    
        while (in_it != in_end)
        {
            if ((*in_it) % 2)
            {
                out_it1 = *in_it;
            }
            else
            {
                out_it2 = *in_it;
            }
            ++in_it;
        }
    
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5};
        auto b = v.crbegin(), e = v.crend();
        while (b != e )
        {
            std::cout << *b << ' ';
            ++b;
        }
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5};
        auto b = v.cbegin(), e = v.cend();
        while (b != e )
        {
            std::cout << *--e << ' ';
        }
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <list>
    
    int main()
    {
        std::list<int> l = {4, 0, 2, 3, 4, 0, 8};
        auto b = l.crbegin(), e = l.crend();
        auto result = std::find(b, e, 0);
        std::cout << *b - *result << std::endl;    //使用8-0来验证查找到的0是最后一个0
        std::cout << std::endl;
        return 0;
    }

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

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <list>
    
    int main()
    {
        std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        std::list<int> l;
        std::copy(v.crbegin() + 2, v.crend() - 3, std::back_inserter(l));
        for (auto i : l)
        {
            std::cout << i << " ";
        }
        return 0;
    }

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

    1.输入迭代器
    *iterator,++iterator,==,!=,->
    2.输出迭代器
    *iterator,++iterator
    3.前向迭代器
    *iterator,++iterator,==,!=,->
    4.双向迭代器
    *iterator,++iterator,--iterator,==,!=.->
    5.随机访问迭代器
    *iterator,++iterator,--iterator,==,!=.->,<,>,+=,-,iterator[n]

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

    list的迭代器属于双向迭代器
    vector的迭代器属于随机访问迭代器

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

    copy要求两个输入和一个输出迭代器
    reverse要求双向迭代器
    unique要求前向迭代器

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

    replace(beg, end, old_val, new_val); //替换beg和end指定范围内所有old_val的值为new_val
    replace_if(beg, end, pred, new_val); //替换beg和end指定范围内使得pred为真的所有元素的值为new_val
    replace_copy(beg, end, dest, old_val, new_val); //将beg和end指定范围内的所有old_val替换为new_val,并将新的序列写入到dest指定的容器
    replace_copy_if(beg, end, dest, pred, new_val); //将beg和end指定范围内使得pred为真的所有元素的值替换为new_val,并将新的序列写入到dest指定的容器

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

    #include <iostream>
    #include <algorithm>
    #include <list>
    
    void elimDups(std::list<std::string>& words)
    {
        words.sort();
    
        words.unique();
    }
    
    int main()
    {
        std::list<std::string> l = {"123", "45", "123", "456", "678", "888", "45"};
        elimDups(l);
        for (auto i : l)
        {
            std::cout << i << " ";
        }
        return 0;
    }
  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/pluse/p/5779086.html
Copyright © 2011-2022 走看看