STL算法,容器,迭代器的设计理念
1.STL容器通过 类模板 技术,实现 数据类型 和 容器模型的分离;
2.迭代器技术 实现了 遍历和操作容器的统一方法
3.STL算法设计理念:通过预定义的函数对象和函数对象实现了数据类型与算法的分离;预定义函数对象处理基本数据类型,函数对象实现了自定义数据类型与算法的分离;
核心思想:函数对象本质是回调函数;
回调函数的思想:实现任务的编写者 和 任务的调用者有效解耦合。
一、STL算法的设计理念
函数对象
一元函数对象、一元谓词
二元函数对象、二元谓词
预定义函数对象
函数适配器
容器算法迭代器的设计理念:
要点:分清楚STL算法返回的值是迭代器 还是 谓词(函数对象)
transform算法的输入,通过迭代器first和last指向的元素作为输入;通过result作为输出;
通过函数对象来做自定义数据类型的运算。
函数对象:重载函数调用操作符的类,其对象常称为函数对象。
他们是行为类似函数的对象,通过:对象名(参数列表)。又称为仿函数,伪函数; 通过重载类的 operator()来实现的。 一元函数对象:函数参数为1个的函数对象 二元函数对象:函数参数为2个
谓词可以是一个仿函数,也可以是一个回调函数
一元谓词 函数参数1个,函数返回值为bool类型
二元谓词 函数参数2个,函数返回值为bool类型
函数对象与普通函数的异同点:
1.调用方式的相似性
template <typename T> class ShowElement { public: void operator()(T &t) //重载了函数调用操作符的类 定义的对象 叫 函数对象 { cout << t << " "; } protected: private: };
template <typename T> //函数模板 void FuncShowElement(T &t) { cout << t << endl; }
void FuncShowElement(int &t) //普通函数 { cout << t << endl; }
void main() { int a = 10; ShowElement<int>showElement; showElement(a); //函数对象的()执行,很像一个函数,是一个仿函数 FuncShoeElement<int>(a); //函数模板 FuncShoeElement(a); //普通函数 }
不同点:函数对象的优势:
函数对象是 类对象,能保持调用状态信息
vector<int>v1; v1.push_back(1); v1.push_back(3); v1.push_back(5); for_each(v1.begin(),v1.end(),ShowElement<int>()); //匿名函数对象 匿名仿函数 for_each(v1.begin(),v1.end(),FuncShowElement); //通过回调函数
for_each算法中 :
函数对象的两种用法:
函数对象做函数参数
函数对象当返回值
for_each算法的 函数对象 是元素 即值传递,不是引用传递。但返回的是一个元素,可以通过返回值记录状态
ShowElement<int>show; show = for_each(v1.begin(),v1.end(),show);//里面show是实参,左值是返回值 show.printN();
一元谓词和STL算法配合使用
template<typename T> class isDiv { public: isDiv(const T& divisor) //拷贝构造函数 { this->divisor = divisor; } bool operator()(T& t) { return (t % divisor == 0); } protected: private: T divisor; } void main() { vector<int>v2; for(int i = 10; i < 33; i++) { v2.push_back(i); } int a = 4; isDiv<int>myDiv(a); //find_if(v2.begin(),v2.end(),myDiv); vector<int>::iterator it; it = find_if(v2.begin(),v2.end(),isDiv<int>(a)); if(it == v2.end()) { cout << "容器中没有被4整除的元素" << endl; } else { cout << "第一个被4整除的元素: " << *it <<endl; } } //查看源码,find_if返回的是迭代器;
二元函数对象,二元谓词:
两个数的比较,加和等;transform();
template<typename T> class sumAdd { public: T operator()(T t1,T t2) { return t1+t2; } } void main() { vector<int>v1,v2; vector<int>v3; v1.push_back(1); v1.push_back(2); v1.push_back(3); v2.push_back(4); v2.push_back(5); v2.push_back(6); v3.resize(10); //前两个参数是一个容器的迭代器参与运算的起点和终点,第三个参数是另一个容器的参与运算的开始位置; //第四个参数是结果存放的位置(可以是v1),第五个参数是函数对象(自己实现业务功能) //返回值是 第四个参数,即 存放结果的迭代器 transform(v1.begin(),v1.end(),v2.begin(),v3.begin(),sumAdd<int>()); }
二元谓词:(比较大小)
bool myCompre(const int& a,const int& b) { retrun a < b; //从小到大排序 }
void main() { vector<int>v(10); for(int i = 0; i < 10; i++) { int tmp = rand()%100; v[i] = tmp; } sort(v.begin(),v.end(),myCompare); }
二元谓词在set集合中的应用:
find默认区分大小写,利用二元谓词让其不区分大小写;
struct compareNoCase { bool operator()(const string& str1,const string& str2) { string str1_; str1_.resize(str1.size()); transform(str1.begin(),str1,end(),str1_.begin(),tolower); string str2_; str2_.resize(str2.size()); transform(str2.begin(),str2.end(),str2_.begin(),tolower) return (str1_ < str2_); } } set<string,compareNoCase>::iterator it = set1.find("aAa");//find函数默认区分大小写 //利用仿函数的set实现了内容全部转化为小写,排序;其内部函数,insert()和find()的()已被重载,都有转化为小写的功能;
预定义函数对象和函数适配器
#include <functional>
plus<int>add; //两个整形数相加 plus<string>add; //字符串连接 sort(v1.begin(),v1.end(),greater<string>());//加谓词后,从大到小排序 //统计出现次数: //equal_to<string>()有两个参数:left参数来自容器,right参数来自sc //bind2nd是函数适配器;把预定义函数对象 和 第二个参数进行绑定 string sc = "ccc"; int num = count_if(v1.begin(),v1.end(),bind2nd(equal_to<string>(),sc)); //bind1st( , );
函数适配器:
STL中已经定义了大量函数对象,但有时候需要对函数返回值进行进一步简单计算,或者填上多余参数,不能直接代入算法。
函数适配器将一种函数对象转化为另一种符合要求的函数对象。
绑定适配器,组合适配器,指针函数适配器,成员函数适配器。
binder1st:将数值绑定到二元函数的第一个参数,适配成一元函数 //bind1st(op,value) binder2nd:将数值绑定到二元函数的第二个参数,适配成一元函数 //bind2nd(op,value) unary_negate:将一元谓词的返回值适配成其逻辑反 //not1(op) binary_negate:将二元谓词的返回值适配成其逻辑反 //not2(op) int num = count(v1.begin(),v1.end(),3); //统计v1中3的个数 //通过 谓词 求大于2的个数 class isGreat { public: isGreat(int i) { m_num = i; } bool operator()(int& num) { if(num > m_num) return true; else return false; } private: int m_num; };
int num1 = count_if(v1.begin(),v1.end(),isGreat(2)); //通过预定义函数对象 求大于2的个数 int num2 = count_if(v1.begin(),v1.end(),bind2nd(greater<int>(),2)); //求 奇数个数 int num3 = count_if(v1.begin(),v1.end(),bind2nd(modulus<int>(),2)); int num4 = count_if(v1.begin(),v1.end(),not1(bind2nd(modulus<int>(),2)));