zoukankan      html  css  js  c++  java
  • 【c++ primer读书笔记】【第10章】泛型算法

    1、泛型算法本身不会执行容器的操作,只会运行于迭代器之上,执行迭代器的操作。算法永远不会改变底层容器的大小。

    2、只读算法:一些算法只会读取其输入范围内的元素,从不改变元素。 对于只读算法,最好使用次cbegin()和cend()。

    find:接受三个参数,前两个指出查找的元素的范围,第三个参数是要查找的元素。返回指向要查找元素的迭代器,若没找到指定元素,返回尾后迭代器。

    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    int main(){
    	vector<int> vec = { 27, 210, 12, 47, 109, 83 };
    	int val = 83;
    	auto result = find(vec.cbegin(), vec.cend(), val);
    	cout << *result << endl;         //输出83
    
    	system("pause");
    	return 0;
    }
    

    accumulate:接受三个参数,前两个指出需要求和的元素的范围,第三个参数是和的初值。返回求和的结果。

    #include<iostream>
    #include<algorithm>
    #include<numeric>
    #include<vector>
    #include<string>
    using namespace std;
    
    int main(){
    	vector<int> vec{ 1, 2, 3, 4 };
    	int val = 0;
    	auto result = accumulate(vec.cbegin(), vec.cend(), val);
    	cout << result << endl; //输出10
    	//string定义了+运算符,能用accumulate函数将string元素连接起来
    	vector<string> svec{ "aaa", "bbb", "vvv" };
    	auto sresult = accumulate(svec.cbegin(), svec.cend(), string(""));
    	cout << sresult << endl;  //输出aaabbbvvv
    
    	system("pause");
    	return 0;
    }
    

    equal:接受三个参数,前两个指出第一个序列中的元素范围,第三个参数表示指向第二个序列首元素的迭代器。判断两个序列是否保存相同的值。假定第二个序列至少与第一个序列一样长。

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<list>
    using namespace std;
    
    int main(){
    	vector<int> vec{ 1, 2, 3, 4 };
    	list<int> li{ 1, 2, 3, 4 };
    	cout << equal(vec.begin(), vec.end(), li.begin()) << endl; //输出1
    	cout << equal(vec.begin() + 1, vec.end(), li.begin()) << endl; //输出0
    	system("pause");
    	return 0;
    }
    

    3、  写容器元素算法:必须确保序列原大小不小于要求写入的元素数目。

    fill:接受三个参数,前两个指出序列中的元素范围,第三个参数表示将这个值赋予序列中的每个元素。

    fill_n:接受一个单迭代器、一个计数值和一个值。将给定值赋予迭代器指向的元素开始的指定个元素。

    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    int main(){
    	vector<int> vec{ 1, 2, 3, 4 };
    	fill(vec.begin(), vec.begin() + vec.size() / 2, 0);
    	for (const auto& c : vec)
    		cout << c << " ";
    	cout << endl;   //输出0 0 3 4
    	//向目的位置迭代器写入数据的算法假定目的位置足够大,能容纳要写入的元素
    	fill_n(vec.begin(), 3, 1);
    	for (const auto& c : vec)
    		cout << c << " ";
    	cout << endl;   //输出1 1 1 4
    
    	system("pause");
    	return 0;
    }
    

    back_inserter:接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<iterator>
    using namespace std;
    
    int main(){
    	vector<int> vec;
    	fill_n(back_inserter(vec),5,0);
        for(const auto& c:vec)
    		cout<<c<<" ";
    	cout<<endl; //输出0 0 0 0 0 
    	system("pause");
    	return 0;
    }
    

    4、  拷贝算法

    copy:接受三个迭代器,前两个表示输入范围,第三个表示目的序列的起始位置。把输入范围中的元素拷贝到目的序列中。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int main(){
    	int ia1[]={1,2,3,4};
    	int ia2[sizeof(ia1)/sizeof(*ia1)];
    	auto ret=copy(begin(ia1),end(ia1),ia2);//ret指向拷贝到ia2的尾元素之后的位置
    	for(const auto& i:ia2)
    		cout<<i<<" ";
    	cout<<endl;   //输出1 2 3 4
    	system("pause");
    	return 0;
    }
    

    5、  重排容器元素算法

    sort:接受两个迭代器,表示排序的元素范围

    unique:将相邻的重复项“消除”,并返回一个指向不重复值范围末尾的迭代器。此位置之后的元素仍存在,但不知道值是什么。

    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<sstream>
    #include<vector>
    using namespace std;
    
    int main(){
    	string str="the quuick red fox jumps over the slow red turtle";
    	stringstream ss(str);
    	string word;
    	vector<string> vec;
    	while(ss>>word)
    		vec.push_back(word);
    
    	sort(vec.begin(),vec.end());
    	for(const auto& i:vec)
    		cout<<i<<" ";
    	cout<<endl;   //输出fox jumps over quuick red slow the the turtle
    
    	auto end_unique=unique(vec.begin(),vec.end());
    	vec.erase(end_unique,vec.end());
    	for(const auto& i:vec)
    		cout<<i<<" ";
    	cout<<endl;   //输出fox jumps over quuick red slow the turtle
    
    	system("pause");
    	return 0;
    }

    6、谓词是一个可调用的表达式,返回结果是能用作条件的值。谓词分一元谓词和二元谓词。

    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<sstream>
    #include<vector>
    using namespace std;
    //二元谓词,比较函数,按长度排序单词
    bool isShorter(const string& s1,const string& s2){
    	return s1.size()<s2.size();
    }
    int main(){
    	string str="the quuick red fox jumps over the slow red turtle";
    	stringstream ss(str);
    	string word;
    	vector<string> vec;
    	while(ss>>word)
    		vec.push_back(word);
    	vector<string> vec2(vec);
    
    	sort(vec.begin(),vec.end(),isShorter);//按长度由短至长排序
    	for(const auto& i:vec)
    		cout<<i<<" ";
    	cout<<endl;   //输出the red fox the red over slow jumps quick turtle
    
    	system("pause");
    	return 0;
    }
    7、lambda表达式具有如下形式

    [capture list](parameter list) -> return type { function body }

    capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表(通常为空)。return type、parameter list和function body分别表示返回类型(必须是尾置返回类型)、参数列表和函数体。可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体。

    与上面isShorter函数完成相同功能的lambda:

    [](const string& s1,const string& s2){ return s1.size()<s2.size(); }

    lambda值捕获

    void fun1(){
    	size_t v1=42;
    	auto f=[v1]{ return v1; };
    	v1=0;
    	auto j=f(); //j为42,f保存了我们创建它时v1的拷贝
    }
    lambda引用捕获
    void fun2(){
    	size_t v1=42;
    	auto f=[&v1]{ return v1; };
    	v1=0;
    	auto j=f(); //j为0,f保存了v1的引用
    }
    lambda隐式捕获:&采用引用捕获方式,=采用值捕获方式
    [=](const string& s1,const string& s2){ return s1.size()>=size; }
    可变lambda:在参数列表首加上关键字mutable,改变被捕获变量的值
    void fun3(){
    	size_t v1=42;
    	auto f=[v1] () mutable { return v1; };
    	v1=0;
    	auto j=f(); //j为43
    }
    8、 参数绑定

    bind函数在头文件functional中,调用bind函数的一般形式为:

    auto newCallable=bind(callable,arg_list);

    newCallable本身是一个可调用的对象,arg_list是一个逗号分割的参数列表,对应给定callable的参数。

    arg_list可能包含形如_n的名字,n是一个整数,这些参数是占位符,表示了newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置。_n定义在一个名为placeholders的命名空间中。

    bind拷贝其参数,当希望传递给bind一个对象又不拷贝它,必须使用ref函数。

    #include<iostream>
    #include<functional>
    using namespace std;
    using namespace std::placeholders;
    
    int add(int a,int b,int c,int d){
    	return a+b+c+d;
    }
    int main(){
    	int a=1,c=2;
    	auto g=bind(add,a,_2,c,_1);
    	cout<<g(3,4)<<endl; //调用add(1,4,2,3);
    
    	system("pause");
    	return 0;
    }

    9、 插入迭代器

    back_inserter 创建一个使用push_back的迭代器 。

    front_inserter 创建一个使用push_front的迭代器。

    inserter创建一个使用insert的迭代器,此函数接受两个参数,这个参数必须是指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。

    #include<iostream>
    #include<list>
    #include<iterator>
    using namespace std;
    
    int main(){
    	list<int> lst{ 1, 2, 3, 4 };
    	list<int> lst2, lst3, lst4;
    
    	copy(lst.cbegin(), lst.cend(), back_inserter(lst2));
    	for (const auto& l : lst2)
    		cout << l << " ";
    	cout << endl; //输出1 2 3 4
    
    	copy(lst.cbegin(), lst.cend(), front_inserter(lst3));
    	for (const auto& l : lst3)
    		cout << l << " ";
    	cout << endl; //输出4 3 2 1
    
    	copy(lst.cbegin(), lst.cend(), inserter(lst4, lst4.begin()));
    	for (const auto& l : lst4)
    		cout << l << " ";
    	cout << endl;  //输出1 2 3 4
    
    	system("pause");
    	return 0;
    }
    

    10iostream迭代器

    istream_iterator迭代器:读取输入流

    ostream_iterator迭代器:向输出流写数据

    #include<iostream>
    #include<list>
    #include<iterator>
    using namespace std;
    
    int main(){
    	list<int> lst;
    	istream_iterator<int> in(cin),eof;
    	while(in!=eof)
    		lst.push_back(*in++);//解引用迭代器,获得从流读取的前一个值
    
    	ostream_iterator<int> out(cout," ");
    	for(const auto& l:lst)
    		*out++=l; //将元素写到cout
    	cout<<endl;
    
    	system("pause");
    	return 0;
    }
    

    11、反向迭代器

    反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器,++iter会移动到前一个元素,--iter会移动到下一个元素。除了forward_list之外,其他的容器都定义了反向迭代器。

    下图显示了一个名为vec的vector上的4种迭代器:


    #include<iostream>
    #include<string>
    #include<iterator>
    #include<algorithm>
    using namespace std;
    
    int main(){
    	string str="FIRST,MIDDLE,LAST";
    	auto comma=find(str.cbegin(),str.cend(),',');
    	cout<<string(str.cbegin(),comma)<<endl; //输出FIRST
    
    	auto rcomma=find(str.crbegin(),str.crend(),',');
    	cout<<string(rcomma.base(),str.cend())<<endl;//输出LAST
    
    	system("pause");
    	return 0;
    }

    用图表示上面各个迭代器:


    12、迭代器类别

    输入迭代器:只读,不写,单遍扫描,只能递增

    输出迭代器:只写,不读,单遍扫描,只能递增

    前向迭代器:可以读写,多遍扫描,只能向前

    双向迭代器:可以读写,多遍扫描,可以递增递减

    随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算。

    13、listforward_list的特定算法

    链表可以改变元素间的链接而不是真的交换它们的值来“交换”元素,因此特定算法的性能比对应的通用版本好很多。

    #include<iostream>
    #include<list>
    using namespace std;
    
    int main(){
    	list<int> lst1,lst2;
    	for(size_t i=1;i!=5;++i)
    		lst1.push_back(i);
    	for(size_t i=6;i!=10;++i)
    		lst1.push_back(i);
    	lst1.merge(lst2); //将lst2的元素合并入lst1,并将元素从lst2删除,lst1和lst2必须有序
    	for(const auto l:lst2)
    		cout<<l<<" ";
    	cout<<endl;
    
    	lst1.remove(5); //将lst1的指定元素删除
    	lst1.reverse();  //将lst1的元素反转
    	for(const auto l:lst1)
    		cout<<l<<" ";
    	cout<<endl;
    
    	list<int> lst3;
    	for(size_t i=20;i!=25;++i)
    		lst3.push_back(i);
    	lst1.splice(lst1.begin(),lst3);//将lst3中的所有元素移动到lst1.begin()之前的位置,并将元素从lst3删除
    	for(const auto l:lst1)
    		cout<<l<<" ";
    	cout<<endl;
    
    	system("pause");
    	return 0;
    }

  • 相关阅读:
    网络配置br0 brtcl
    vlan pvid vid access口 trunk口
    虚拟化设置
    debian配置网络
    ps -a,job,netstat,daemons
    windows用命令行查看硬件信息
    查看linux硬件信息
    ruby send respond_to
    打开Win7休眠模式和离开模式的方法
    vim手册
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4495572.html
Copyright © 2011-2022 走看看