Loading

C++Primer第五版 第十章 泛型算法

习题首页

10.1 概述

1 泛型算法:实现了一些经典算法的公共接口,如排序和搜索,可以用于不同类型的元素和多种容器类型

2 基本上都定义在algorithm和numeric两个头文件中

3 迭代器令算法不依赖于容器,依赖于元素类型的操作

练习10.1

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

using namespace std;

int main() {
	int t, n;
	vector<int> vec;
	cout << "请输入int序列个数:" << endl;
	cin >> n;
	cout << "请输入int序列:" << endl;
	for (int i = 0;i < n;i++) {
		cin >> t;
		vec.push_back(t);
	}
	cout << "请输入要统计的值:" << endl;
	int num;
	cin >> num;
	cout << count(vec.begin(), vec.end(), num) << endl;
	
	system("pause");
	return 0;
}

练习10.2

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

using namespace std;

int main() {
	int num = 0,t = 0;
	string s1;
	list <string> lst;
	cout << "请输入字符串序列数量" << endl;
	cin >> t;
	cout << "请输入" << t << "个字符串" << endl;
	for (int i = 0; i < t; i++){
		cin >> s1;
		lst.push_back(s1);
	}
	cout << "请输入要统计的字符串:" << endl;
	string s2;
	cin >> s2;
	cout << count(lst.begin(), lst.end(), s2) << endl;

	system("pause");
	return 0;
}

10.2 初识泛型算法

1 标准库基本上都是对一个范围内的容器进行操作,所以参数中总会有两个表示范围的迭代器

2 对于读取而不改变元素的算法,最好使用cbegin()和cend(),否则用begin()和end()

练习10.3

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

using namespace std;

int main() {
	vector<int> vec = { 1,2,3 };
	int sum = accumulate(vec.cbegin(), vec.cend(), 0);
	cout << sum << endl;
	return 0;
}

练习10.4

将初值设定为0,表明返回值为int类型,使用之后,会将double转换为int,损失精度

练习10.5

equal会比较指针地址,而不是字符串值,比较的结果与string类型的不一致。

练习10.6

fill_n(vec.begin(),vec.size(),0);//注意其三个参数的意义

练习10.7

(a):lst和vec之间的大小未保证相同,vec.resize(lst.size)

(b):reverse是改变容器容量的,并没有改变其大小,用resize()

练习10.8

算法只是产生了一个插入迭代器,然后使用这个迭代器进行插入操作。

练习10.9

#include<iostream>
#include<numeric>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

void elimDups(vector<string> &words) {
	sort(words.begin(), words.end());
	auto end_unique = unique(words.begin(), words.end());
	cout << "unique后:";
	for (auto i : words) {
		cout << i << " ";
	}
	cout << endl;
	cout << "erase后:";
	words.erase(end_unique, words.end());
	for (auto i : words) {
		cout << i << " ";
	}
	cout << endl;
}

int main() {
	vector<string> words = { "I", "love", "you", "I", "love", "you", "I" };
	elimDups(words);
	system("pause");
	return 0;
}

练习10.10

算法只作用于迭代器,而不直接对容器进行操作。

练习10.11

#include<iostream>
#include<numeric>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

void elimDups(vector<string> &words) {
	cout << "isShorter后:";
	stable_sort(words.begin(), words.end(),isShorter);
	auto end_unique = unique(words.begin(), words.end());
	cout << "unique后:";
	for (auto i : words) {
		cout << i << " ";
	}
	cout << endl;
	cout << "erase后:";
	words.erase(end_unique, words.end());
	for (auto i : words) {
		cout << i << " ";
	}
	cout << endl;
}

int main() {
	vector<string> words = { "I", "love", "you", "I", "love", "you", "I" };
	elimDups(words);
	system("pause");
	return 0;
}

练习10.12

bool compareIsbn(const Sales_data &a, const Sales_data &b) {
        return a.isbn() < b.isbn();
}

练习10.13

#include<iostream>
#include<numeric>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;

bool cmp(const string &a) {
	return a.size() >= 5;
}

int main() {
	vector<string> words = { "the","quick","red","fox","jumps","over","the","slow","red","turtle" };
	partition(words.begin(), words.end(), cmp);
	for (auto &i : words) {
		cout << i << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

练习10.14

#include<iostream>
using namespace std;
int main() {
	auto f = [](int a,int b) {return a + b;};
	cout << f(1, 2) << endl;
	return 0;
}

练习10.15

#include<iostream>
using namespace std;

int main() {
	int a = 1;
	auto f = [a](int b) {return a + b;};
	cout << f(2) << endl;
	
	system("pause");
	return 0;
}

练习10.16

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

using namespace std;

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

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 wc = find_if(words.begin(), words.end(),
		[sz](const string &a)
			{ return a.size() >= sz; });
	auto count = words.end() - wc;
	cout << count << endl;
	for(const auto s : words)
		cout << s << " ";
	cout << endl;
}

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

	biggies(vs, 5);

	return 0;
}

练习10.17

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
 
class Sales_data
{
public:
	Sales_data();
	Sales_data(string s):_isbn(s)//列表初始化格式(:类内变量名(初始化值),)
	{
 
	}
	string isbn()
	{
		return _isbn;
	}
	string _isbn;
};
 
int main(int argc, char**argv)
{
	Sales_data a("because");//初始化对象
	Sales_data b("I");
	Sales_data c("Like");
	Sales_data d("your");
	Sales_data e("beautiful");
	Sales_data f("eyes");
 
	vector<Sales_data> vec1;//VS2010不支持列表初始化
	vec1[0] = a;
	vec1[1] = b;
	vec1[2] = c;
	vec1[3] = d;
	vec1[4] = e;
	vec1[5] = f;
 
	stable_sort(vec1.begin(),vec1.end(),[](Sales_data s1, Sales_data s2){return s1.isbn().size() < s2.isbn().size();});//排序
	cout<<"排序后的vector:";
	for(int i = 0; i < vec1.size(); ++i)
	{
		cout<<vec1[i].isbn()<<" ";
	}
 
	return 0;
}

练习10.18-19

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

using namespace std;

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

void biggies(vector<string> &words, vector<string>::size_type sz)
{
	elimDups(words);
	auto wc = partition(words.begin(), words.end(),
		[sz](const string &a)
	{ return a.size() >= sz; });
    
//auto wc = stable_partition(words.begin(), words.end(),
//[sz](const string &a)
//{ return a.size() >= sz; });

	auto count = words.end() - wc;
	cout << count << endl;
	for (const auto s : words)
		cout << s << " ";
	cout << endl;
}

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

	biggies(vs, 5);
	system("pause");
	return 0;
}

练习10.20

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

using namespace std;

int main()
{
	vector<string> words = { "the","quick","red","fox","jumps","over","the","slow","red","turtle" };
	string::size_type sz = 6;
	auto wc = count_if(words.begin(), words.end(),
		[sz](const string &a)
	{ return a.size() >= sz; });
	cout << wc << endl;
	system("pause");
	return 0;
}

练习10.21

#include<iostream>
#include<algorithm>

using namespace std;

int main() {
	int v = 5;
	auto f = [&v]()->bool
	{
		if (v <= 0) return false;
		else {
			--v;
			return true;
		}
	};
	while (f()) {
		cout << v << endl;
	}
	system("pause");
	return 0;
}

练习10.22

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
 
bool func(string &s)
{
	return s.size()<=6;
}
int main(int argc, char**argv)  
{  
	string a[10] = {"diuwudh","udh","dewiudh","wudh","diutrwu","h","diuw","diuwudhg257","h","d"};  
	vector<string> vec1(a,a+10);//利用数组初始化vector  
	cout<<"长度小于等于6的字符串有"<<count_if(vec1.begin(),vec1.end(),func)<<"个";  
 
	return 0;  
}  

练习10.23

n表示占位符的个数的话,bind的参数数为n+1个,多出来一个参数是为了让它能够找到自己。

练习10.24

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

using namespace std;
bool check_size(string &s, int sz)
{
	return s.size() < sz;
}

int main()
{
	vector<int> vi = { 1,2,3,4,5,6 };
	string s("aaaa");

	auto iter = find_if(vi.begin(), vi.end(), bind(check_size, s, placeholders::_1));

	cout << *iter << endl;
	system("pause");
	return 0;
}

练习10.25

#include<iostream>  
#include<string>  
#include<vector>  
#include<algorithm>  
#include<numeric>  
#include<functional>
using namespace std;
using namespace placeholders;//占位符的命名空间
 
void elimDups(vector<string> &s)  
{  
	sort(s.begin(),s.end());//sort排序  
	vector<string>::iterator str = unique(s.begin(),s.end());//unique排序  
	s.erase(str,s.end());//erase()操作      
}  
bool check_size(const string &s, string::size_type sz)
{
	return s.size()<=sz;
}
void biggis(vector<string> &s, vector<string>::size_type sz)  
{  
	elimDups(s);//字典排序、删除重复  
	stable_sort(s.begin(),s.end(),[](const string &a,const string &b){return a.size()<b.size();});//按长度排序  
	auto it1 = partition(s.begin(),s.end(),bind(check_size,_1,sz)/*[sz](const string &s){return s.size()<=sz;}*/);  
	for (it1; it1 != s.end(); ++it1)  
	{  
		cout<<*it1<<" ";  
	}  
}  
int main(int argc, char**argv)  
{  
	string a[10] = {"diuwudh","udh","diudh","wudh","diuwu","h","diuw","diuwudhg257","h","d"};  
	vector<string> vec1(a,a+10);//利用数组初始化vector  
	biggis(vec1,4);//找出长度大于4的字符串  
 
	return 0;  
}  

10.4 再探迭代器

知识点1:几种特殊的迭代器—实际上相当于一个泛型算法,接受一个容器作为参数,产生一个迭代器,将元素插入容器之中
插入迭代器:这些迭代器绑定到容器上,可以用来向容器插入元素

流迭代器:绑定到输入输出流上,用来遍历所有关联的IO流

反向迭代器:向后移动而不是向前移动,出了forward_list其他容器都有

移动迭代器:移动容器中的元素

知识点2:插入器,接受一个容器作为参数,生成一个迭代器,可以向容器中添加元素。++it,it++,*it都不会产生任何效果,只能返回it(插入迭代器),it = t 在it指向的位置插入元素t。

练习10.26

插入迭代器分为三种:back_inserter()创建一个使用push_back的迭代器,front_inserter()创建一个push_front的迭代器,inserter()创建一个insert迭代器,接受两个参数。插入到指定迭代器之前。(前提是容器必须支持push_back()的操作)。front_insert()最为特殊,总是将元素插在容器之首位置。

练习10.27

知识点:unique_copy():拷贝不重复元素,back_insert():插入迭代器(需包含iterator头文件)

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;


int main() {

	vector<string> vec = { "red", "black", "green", "blue", "red", "green", "yellow" };
	list<string> lst;
	sort(vec.begin(), vec.end());
	unique_copy(vec.begin(), vec.end(),inserter(lst,lst.begin()));
	for (auto &s : lst){
		cout << s << " ";
	}
	system("pause");
	return 0;
}

练习10.28

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;


int main() {

	vector<int> vec = { 1,2,3,4,5,6,7,8,9 };
	vector<int> vec1, vec2, vec3;

	copy(vec.begin(), vec.end(),inserter(vec1,vec1.begin()));
	for (auto &s1 : vec1){
		cout << s1 << " ";
	}
	cout << endl;
	copy(vec.begin(), vec.end(), back_inserter(vec2));
	for (auto &s2 : vec1){
		cout << s2 << " ";
	}
	cout << endl;
	copy(vec.begin(), vec.end(), front_inserter(vec3));//不支持push_front
	for (auto &s3 : vec1){
		cout << s3 << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

练习10.29

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main() {

	vector<string> vec1;
	ifstream in1("1.txt");//不允许使用不完整类型,是因为没有头文件~~
	istream_iterator<string> str(in1);
	istream_iterator<string> end;//尾后迭代器

	copy(str, end, back_inserter(vec1));//存入vec1

	for (int i = 0; i < vec1.size(); ++i)
	{
		cout << vec1[i] << endl;
	}

	cout << endl;
	system("pause");
	return 0;
}

练习10.30

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main() {

	istream_iterator<int> in_iter(cin), eof;

	ostream_iterator<int> out_iter(cout, " ");

	vector<int> ivect(in_iter, eof);

	sort(ivect.begin(), ivect.end());

	copy(ivect.cbegin(), ivect.cend(), out_iter);

	cout << endl;
	system("pause");
	return 0;
}

练习10.31

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main() {

	istream_iterator<int> in_iter(cin), eof;

	ostream_iterator<int> out_iter(cout, " ");

	vector<int> ivect(in_iter, eof);

	sort(ivect.begin(), ivect.end());

	unique_copy(ivect.cbegin(), ivect.cend(), out_iter);

	cout << endl;
	system("pause");
	return 0;
}

练习10.32

#include <iostream>
#include <vector>
#include <string>
#include <istream>
#include <iterator>
#include <algorithm>
#include <numeric>
 
using namespace std;
 
//使用简化的类
class Sales_Data
{
public:
    Sales_Data() {}
    Sales_Data( string s ) : bookNo( s )
    {
 
    }
    string getBookNo()
    {
        return bookNo;
    }
 
    friend istream& operator >>( istream &in, Sales_Data &s )
    {
        in >> s.bookNo;
        return in;
    }
    friend string operator+( string s1, Sales_Data &s )
    {
        return s1 + s.bookNo;
    }
    friend ostream& operator<<( ostream& out, Sales_Data &s )
    {
        out << s.bookNo;
        return out;
    }
    friend bool operator ==( const Sales_Data &s1, const Sales_Data &s2 )
    {
        return s1.bookNo == s2.bookNo;
    }
private:
    string bookNo;
};
 
bool compareIsbn( Sales_Data &s1, Sales_Data &s2 )
{
    return s1.getBookNo() > s2.getBookNo();
}
 
//by zhaocl
int main()
{
    //使用cin,需要类重载>>操作符
    istream_iterator<Sales_Data> sale_iter( cin ), eof;
 
    //输入的元素拷贝到vector中
    vector<Sales_Data> sale_vec( sale_iter, eof );
 
    //排序
    sort( sale_vec.begin(), sale_vec.end(), compareIsbn );
 
    //求和,需要类重载+操作符
    string s = "biu";
    cout << accumulate( sale_vec.begin(), sale_vec.end(), s ) << endl;
 
    //使用find,因为要比较所以需要类重载==操作符
    s = "biu005";
    auto iter = find( sale_vec.begin(), sale_vec.end(), s );
 
    //因为输出,所以类需要重载<<操作符
    if( iter != sale_vec.end() )
    {
        cout << "find:" << *iter << endl;
    }
    else
    {
        cout << "not find " << s << endl;
    }
 
    system( "pause" );
    return 0;
}

练习10.33

/*
编写程序,接受三个参数:一个输入文件和两个输出文件的文件名。
输入文件保存的应该是整数。使用istream_iterator 读取输入文件。
使用ostream_iterator将奇数写入第一个输出文件,每个值后都跟一个空格。
将偶数写入第二个输出文件,每个值都独占一行。
*/
 
#include <iostream>
#include <iterator>
#include <vector>
#include <fstream>
 
using namespace std;
 
	
int main(int argc, char ** argv)
{
	if (argc != 4)
	{
		cout << "程序使用格式为:本程序名称+空格+输入文件+空格+奇数输出文件名称+空格+偶数输出文件名称" << endl;
		return 0;
	}
	ifstream myifstream(argv[1]);
	ofstream myofstream1(argv[2]);
	ofstream myofstream2(argv[3]);
 
	vector<int> ivect;
	istream_iterator<int> fin(myifstream), eof;
	ostream_iterator<int> fout1(myofstream1, " ");
	ostream_iterator<int> fout2(myofstream2,"\r\n");
 
	copy(fin, eof, back_inserter(ivect)); //读取文件内的值到vector中
	for (auto a : ivect)
	{
		if (a % 2)
			fout1 = a; //为奇数输出到奇数文件
		else
			fout2 = a; //为偶数输出到偶数文件
	}
 
	return 0;
}

练习10.34

#include<vector>  
#include<algorithm>  
#include<numeric>  
#include<functional>
#include<iterator>
using namespace std;

 
int main(int argc, char**argv)  
{  
	vector<int> vec = { 0, 1, 2, 3, 4, 5, };
	for (auto it = vec.crbegin(); it != vec.crend(); ++it){
		cout << *it << endl;
	}
 
	return 0;  
} 

练习10.35

#include<iostream>  
#include<fstream>
#include<string>  
#include<vector>  
#include<algorithm>  
#include<numeric>  
#include<functional>
#include<iterator>
using namespace std;
 
int main(int argc, char**argv)  
{  
	vector<int> vec = { 0, 1, 2, 3, 4, 5, };
	for (auto it = vec.end(); it != vec.begin(); --it){
		cout << *(it-1) << endl;
	}
 
	return 0;  
}  

练习10.36

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main(int argc,char **argv) {

	list<int> lst = { 0, 1, 2, 3, 4, 5, };
	cout << *find(lst.rbegin(), lst.rend(), 0);
	system("pause");
	return 0;
}

练习10.37

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main(int argc,char **argv) {

	vector<int> vec = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	list<int> lst;
	copy(vec.rbegin() + 3, vec.rend() - 2, back_inserter(lst));
	
	for (auto it : lst){
		cout << it << " ";
	}
	system("pause");
	return 0;
}

练习10.38

P366

练习10.39

list:双向迭代器。vector:随机访问迭代器

练习10.40

copy的三个参数,第一、二个是输入迭代器,第三个是输出迭代器

reverse肯定是需要双向迭代器的

unique是前向迭代器

练习10.41

算法的命名规范:_if 非重载,满足谓词条件的版本。_copy拷贝版本的算法

(a):遍历beg到end,找到oldVal就用newVal替换

(b):遍历beg到end,找到满足pred条件的就用newVal替换

(c):遍历beg到end,找到oldVal就用newVal替换,并将其拷贝至dest

(d):遍历beg到end,找到满足pred条件的就用newVal替换,并将其拷贝至dest

练习10.42

知识点1:sort()需要随机访问迭代器,所以不能用于list和forward_list.

知识点2:对于list和forward_list应优先使用其成员函数版本的算法,皆返回void.

知识点3:remove()删除元素,reverse()反转元素顺序,sort()排序,unique()删除相同元素

知识点4:链表类型还定义了splice成员算法,其实链表数据结构所特有的,主要用于合并两个链表

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <list>
#include <deque>
#include <forward_list>
#include <algorithm>
#include<numeric>
using namespace std;

int main(int argc,char **argv) {

	
	list<string> lst = { "abd", "acc", "ash", "acc", "zxc", "zx", "zx", "zxc" };
	lst.sort();//使用其成员函数版本的算法,排序
	lst.unique();
	for (auto it : lst){
		cout << it << " ";
	}
	system("pause");
	return 0;
}
posted @ 2020-07-09 13:53  小森林呐  阅读(185)  评论(0编辑  收藏  举报