Chapter 10. Generic Algorithms

来源:互联网 发布:魔兽7..0mac版插件 编辑:程序博客网 时间:2024/06/03 13:53

练习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>v;v.reserve(10);fill_n(v.begin(), 10, 0);
(a)Fixed: added this statement :vec.resize(lst.size());

vector<int>vec;list<int>lst;int i;while (cin >> i)lst.push_back(i);vec.resize(lst.size());copy(lst.cbegin(), lst.cend(), vec.begin());

Cause Algorithms that write to a destination iterator assume the destination is large enough to hold the number of elements being written.

    Another way to fix bug :

   copy(lst.cbegin(), lst.cend(), back_inserter(vec));

(b)Fixed: 1. use v.resize(10);
or 2. use      fill_n(std::back_inserter(v), 10, 0);

vector<int>v;v.resize(10);fill_n(v.begin(), 10, 0);

 c.reserve(n);分配至少能容纳n个元素的内存空间。

 vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
     reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。

     resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的

 只读算法:

#include<numeric>// sum the elements in vec starting the summation with the value 0int sum = accumulate(vec.cbegin(), vec.cend(), 0);
string sum = accumulate(v.cbegin(), v.cend(), string(""));

得意Best Practices

Ordinarily it is best to usecbegin()andcend()  with algorithms that read, but do not write, the elements.

Another read-only algorithm is equal, which lets us determine whether two sequences hold the same values.

// roster2 should have at least as many elements as roster1equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());

Algorithms That Write Container Elements写容器元素的算法

fill(vec.begin(), vec.end(), 0); // reset each element to 0// set a subsequence of the container to 10fill(vec.begin(), vec.begin() + vec.size()/2, 10);
back_inserter定义在头文件iterator

vector<int> vec; // empty vectorauto it = back_inserter(vec); // assigning through it adds elements to vec*it = 42; // vec now has one element with value 42

vector<int> vec; // empty vector // ok: back_inserter creates an insert iterator that adds elements to vecfill_n(back_inserter(vec), 10, 0); // appends ten elements to vec
Copy Algorithms拷贝算法

int a1[] = { 0,1,2,3,4,5,6,7,8,9 };int a2[sizeof(a1) / sizeof(*a1)]; // a2 has the same size as a1  // ret points just past the last element copied into a2auto ret = copy(begin(a1), end(a1), a2); // copy a1 into a2

// replace any element with the value 0 with 42replace(ilst.begin(), ilst.end(), 0, 42);
This call replaces all instances of 0 by 42
// use back_inserter to grow destination as neededreplace_copy(ilst.cbegin(), ilst.cend(),back_inserter(ivec), 0, 42);
After this call, ilst is unchanged, and iveccontains a copy ofilst with the
exception that every element in ilst with the value 0 has the value 42 inivec.

练习10.9: 

#include <iostream>#include <string>#include <vector>#include <algorithm>// print containers like vector,deque, list, etc.template <typename Sequence> auto println(Sequence const& seq) -> std::ostream &{for (auto const& elem : seq) std::cout << elem << " ";return std::cout << std::endl;}auto eliminate_duplicates(std::vector<std::string>& vs)-> std::vector<std::string> &{std::sort(vs.begin(), vs.end());println(vs);auto new_end = std::unique(vs.begin(), vs.end());println(vs);vs.erase(new_end, vs.end());return vs;}int main(){std::vector<std::string> vs{ "a", "v", "a", "s", "v", "a", "a" };println(vs);println(eliminate_duplicates(vs));system("pause");return 0;}
运行结果:



练习10.11:编写程序,使用stable_sort和is_shorter将传递给你的elimdups版本的vector排序。

#include <iostream>#include <string>#include <vector>#include <algorithm>#include <numeric>#include <list>template<typename Sequence>inline std::ostream& println(Sequence const &seq){for (auto const& elem : seq)std::cout << elem << "  ";std::cout << std::endl;return std::cout;}inline bool is_shorter(std::string const&lhs, std::string const& rhs){return lhs.size() < rhs.size();}void elimdups(std::vector<std::string>&vs){std::sort(vs.begin(), vs.end());auto new_end = std::unique(vs.begin(), vs.end());vs.erase(new_end, vs.end());}int main(){std::vector<std::string>v = { "abc","acb","bac","bca","cab","cba","abc","acb","123","123","1234","1234","Hi" };std::cout << "原始输入:"; println(v); std::cout << std::endl;elimdups(v);std::cout << "排序并去除相同元素:"; std::cout << std::endl;println(v); std::cout << std::endl; std::stable_sort(v.begin(), v.end(),is_shorter);//stable_sort保持等长元素的字典序std::cout << "加入等长元素排序(练习10.11):"; std::cout << std::endl;println(v); std::cout << std::endl;system("pause");return 0;}
运行结果:



练习10.13:

#include <iostream>#include <string>#include <vector>#include <algorithm>bool predicate(const std::string& s){return s.size() >= 5;}int main(){auto v = std::vector<std::string>{ "a","as","aasss","aaaaassaa","aaaaaabba","aaa" };auto pivot = std::partition(v.begin(), v.end(), predicate);//接受一个谓词,true在前,false在后,返回最后一个true元素之后的位置for (auto it = v.cbegin(); it != pivot; ++it) std::cout << *it << " ";std::cout << std::endl;system("pause");return 0;}

练习10.16:

#include <iostream>#include <string>#include <vector>#include <algorithm>void elimdups(std::vector<std::string>&vs){std::sort(vs.begin(), vs.end());auto new_end = std::unique(vs.begin(), vs.end());vs.erase(new_end, vs.end());}void biggies(std::vector<std::string>&vs, std::size_t sz){using std::string;elimdups(vs); //sort by size,but maintain alphabetical order for same size.std::stable_sort(vs.begin(), vs.end(), [](string const & lhs, string const &rhs) {return lhs.size() < rhs.size(); });//get an iterator to the first one whose size() is >=szauto wc = std::find_if(vs.begin(), vs.end(), [sz](string const &s) {return s.size() >= sz; });//print the biggiesstd::for_each(wc, vs.end(), [](const string&s) {std::cout << s << "  "; });}int main(){std::vector<std::string> v{ "1234", "1234", "1234", "hi~","alan", "alan", "cp","a","adfdsgfsdgf" };std::cout << " Ex 10.16:";biggies(v, 3);std::cout << std::endl;system("pause");return 0;}



关于std::for_each的用法示例:

#include <vector>#include <algorithm>#include <iostream> struct Sum {    Sum() { sum = 0; }    void operator()(int n) { sum += n; }     int sum;}; int main(){    std::vector<int> nums{3, 4, 2, 9, 15, 267};     std::cout << "before: ";    for (auto n : nums) {        std::cout << n << " ";    }    std::cout << '\n';     std::for_each(nums.begin(), nums.end(), [](int &n){ n++; });    Sum s = std::for_each(nums.begin(), nums.end(), Sum());     std::cout << "after:  ";    for (auto n : nums) {        std::cout << n << " ";    }    std::cout << '\n';    std::cout << "sum: " << s.sum << '\n';}
输出:

before: 3 4 2 9 15 267
after:  4 5 3 10 16 268
sum: 306

练习10.18/10.19:

#include <iostream>#include <string>#include <vector>#include <algorithm>//! from ex 10.9void elimdups(std::vector<std::string>& vs){    std::sort(vs.begin(), vs.end());    auto new_end = std::unique(vs.begin(), vs.end());    vs.erase(new_end, vs.end());}//! ex10.18void biggies_partition(std::vector<std::string>& vs, std::size_t sz){    elimdups(vs);    auto pivot = partition(vs.begin(), vs.end(), [sz](const std::string& s) {        return s.size() >= sz;    });    for (auto it = vs.cbegin(); it != pivot; ++it) std::cout << *it << " ";}//! ex10.19void biggies_stable_partition(std::vector<std::string>& vs, std::size_t sz){    elimdups(vs);    auto pivot =        stable_partition(vs.begin(), vs.end(),                         [sz](const std::string& s) { return s.size() >= sz; });    for (auto it = vs.cbegin(); it != pivot; ++it) std::cout << *it << " ";}int main(){    //! ex10.18    std::vector<std::string> v{"the",  "quick", "red",  "fox", "jumps",                               "over", "the",   "slow", "red", "turtle"};    std::cout << "ex10.18: ";    std::vector<std::string> v1(v);    biggies_partition(v1, 4);    std::cout << std::endl;    //! ex10.19    std::cout << "ex10.19: ";    std::vector<std::string> v2(v);    biggies_stable_partition(v2, 4);    std::cout << std::endl;    return 0;}//! output ://!// ex10.18: turtle jumps over quick slow// ex10.19: jumps over quick slow turtle

值捕获:

void fcn1(){size_t v1 = 42;//局部变量auto f = [v1] {return v1;};//将V1拷贝到名为f的可调用对象v1 = 0;auto j = f();//j为42;f保存了我们创建它时v1的拷贝}


引用捕获:

void fcn2(){size_t v1 = 42;//局部变量auto f2 = [&v1] {return v1;};//对象f2包含v1的引用v1 = 0;auto j = f2();//j为0;f2保存v1的引用,而非拷贝}


惊讶Warning!当以引用方式捕获一个变量时,必须保证在lambda执行时变量是存在的。一般来说,我们应该尽量减少捕获的数据量,来避免潜在的捕获导致的问题。而且,如果可能的话,应该避免捕获指针或引用。


可变lambda

void fcn3(){size_t v1 = 42;//局部变量auto f = [v1]()mutable {return ++v1; };//f可以改变它所捕获的变量的值v1 = 0;auto j = f();//j为43}void fcn4(){size_t v1 = 42;//局部变量,v1是一个非const变量的引用auto f2 = [&v1] {return ++v1; };//可以通过f2中的引用来改变它v1 = 0;auto j = f2();//j为1}


指定lambda返回类型

#include <iostream>#include <string>#include <cctype>#include <vector>#include <algorithm>int main(){std::vector<int>vi{ 1,2,3,-1,-2,-3,4,5,6,-4,-5,-6 };transform(vi.begin(), vi.end(), vi.begin(), [](int i) {return i < 0 ? -i : i; });for (auto ele : vi)std::cout << ele << "  ";std::cout<<std::endl;std::string s("hello,luwenwen!");std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))std::toupper);std::cout << s;std::cout << std::endl;system("pause");return 0;}

使用尾置返回类型:

transform(vi.begin(), vi.end(), vi.begin(), [](int i)->int {if (i < 0)return-i; else return i; });


练习10.20:统计有多少单词长度超过6

#include <algorithm>#include <iostream>#include <string>#include <vector>using std::vector;using std::string;using std::cout;using std::endl;int main(){vector<string> words{ "cppprimer", "pezy",    "learncpp","greater",   "rewrite", "programmer" };cout << std::count_if(words.cbegin(), words.cend(), [](const string& word) {return word.size() > 6;}) << std::endl;system("pause");}

练习10.21:

#include <iostream>using std::cout;using std::endl;int main(){int local_val = 7;// local int variableauto decrement_to_zero = [&local_val]() {if (local_val == 0)return true;else {--local_val;return false;}};while (!decrement_to_zero()) cout << local_val << ",";system("pause");}
运行结果:



原创粉丝点击