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;
}