Chapter 10. Generic Algorithms

练习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 0
	int 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 roster1
equal(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 10
fill(vec.begin(), vec.begin() + vec.size()/2, 10);
back_inserter定义在头文件 iterator

	vector<int> vec; // empty vector
	auto 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 vec
	fill_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 a2
	auto ret = copy(begin(a1), end(a1), a2); // copy a1 into a2

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

练习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 >=sz
	auto wc = std::find_if(vs.begin(), vs.end(), [sz](string const &s) {return s.size() >= sz; });
	//print the biggies
	std::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.9
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());
}

//! ex10.18
void 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.19
void 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 variable
	auto 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");
}
运行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值