容器的内容整合整理在上周内容里,这次内容也是很散,重点整理仿函数和非变易算法。关于非变易算法,晚上流传的材料大部分都是例子和结果。所以这次的笔记虽然内容不多,却会意外的长。整理内容来源Bill’ Blog和趣味集。
STL各个组件组件关系如图,其中仿函数应该是体积最小的,并且观念最简单,实现最容易的一个。它扮演的一种“策略”的角色,可以让STL更具灵活性。在STL的历史上,仿函数(functor)是早期的命名,C++标准规格定下来后才改为函数对象(function object)。函数对象对调用者而言可以向函数调用一样的被调用,而对被调用者而言则是以对象所定义的函数调用操作符(function call operator)。在C++中,函数调用操作符是指左右小括号“()”,该操作符是可以重载的。许多STL算法都提供了两个版本,一个用于一般情况(例如排序是所用的operator<以递增方式排列),一个用于特殊情况(例如排序时按照使用者自定义的大小关系进行排序)。有些类似C语言里的函数指针,但函数指针无法满足STL对抽象性的要求,也不能喝STL其他组件搭配。
关于仿函数的可适配关键。STL仿函数的可配接性(adaptability),即函数可以被配接器修饰,彼此串接。为了拥有配接能力,每一个仿函数必须定义自己的相应型别(associate types),也必须依照规定定义自己的5个相应型别一样。这样做是为了让配接器能够获得函数的一些特性。相应型别都只是一些 typedef,所有必要操作在编译期就就全部完成了,对程序的执行效率没有任何影响,不带来任何额外负担。仿函数相应型别主要用来表示函数的参数型别和返回值型别,为了方便,stl_function.h 中定义了两个基类,分别是 unary_function 和 binary_function,分别表示一元函数和二元函数,其中都是一些型别的定义,仿函数只需要继承其中一个类,就可以拥有配接能力。
unary_function:该类用来封装一元函数的参数型别和返回值型别,其定义为:
template <class _Arg, class _Result>
struct unary_function {
typedef _Arg argument_type; // 参数型别
typedef _Result result_type; // 返回值型别
};
仿函数可以继承该类,这样用户就可以取得该仿函数的参数型别,并以相同方法获得其返回值:
template <class _Tp>
struct negate : public unary_function<_Tp,_Tp> { // 仿函数 negate 继承 unary_function
_Tp operator()(const _Tp& __x) const { return -__x; }
};
template <class _Predicate>
class unary_negate : public unary_function<typename _Predicate::argument_type, bool> {
protected:
_Predicate _M_pred;
public:
explicit unary_negate(const _Predicate& __x) : _M_pred(__x) {}
bool operator()(const typename _Predicate::argument_type& __x) const { // 获取参数的型别argument_type
return !_M_pred(__x);
}
};
binary_function:该类用来封装二元函数的参数一、参数二型别和返回值类型,仅比一元函数多了一个输入参数型别的定义而已,其定义为:
template <class _Arg1, class _Arg2, class _Result>
struct binary_function {
typedef _Arg1 first_argument_type; // 参数一型别
typedef _Arg2 second_argument_type; // 参数二型别
typedef _Result result_type; // 返回值型别
};
template <class _Tp>
struct plus : public binary_function<_Tp,_Tp,_Tp> { // 仿函数 plus 继承 binary_function
_Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x + __y; }
};
STL内建的仿函数若是按照功能划分可分为算术运算,关系运算,逻辑运算三类,任何任何应用程序欲使用STL内建的仿函数,需要包含 <functional> 头文件,而这些仿函数的实际实现都在 stl_function.h 中。
算术类(Arithmetic)仿函数:主要包括加法(plus)、减法(minus)、乘法(multiplies)、除法(divides)、取模(modulus)、否定(negation)等运算。例:
template <class _Tp>
struct plus : public binary_function<_Tp,_Tp,_Tp> {
_Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x + __y; } // 加法,减、乘、除、取模类似
};
template <class _Tp>
struct negate : public unary_function<_Tp,_Tp> {
_Tp operator()(const _Tp& __x) const { return -__x; }
};
关系运算类(Relational)仿函数:主要有等于(equal_to)、不等于(not_equal_to)、大于(greater)、大于等于(greater_equal)、小于(less)、小于等于(less_equal)等六种运算。例:
template <class _Tp>
struct equal_to : public binary_function<_Tp,_Tp,bool> {
bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; } // 相等,其他类似 !=, >, <, >=, <=
};
逻辑运算类(Logical)仿函数:主要是与(logical_and)、或(logical_or)、非(logical_not)三种逻辑运算。例:
template <class _Tp>
struct logical_and : public binary_function<_Tp,_Tp,bool> {
bool operator()(const _Tp& __x, const _Tp& __y) const { return __x && __y; } // 与,或(||)类似
};
template <class _Tp>
struct logical_not : public unary_function<_Tp,bool>{
bool operator()(const _Tp& __x) const { return !__x; } // 非
};
C++ STL的非变易算法(Non-mutating algorithms):是一组不破坏函数数据的模板函数,用来对序列数据进行逐个处理、元素查找、子序列搜索、统计和匹配,基本上可用于各种容器。C++ STL算法库中的非变易算法,是一些原则上不会变更操作数据的算法。包括:逐个查找算法、元素搜索算法、元素统计算法、序列匹配算法、子序列搜索算法、这些函数均包含于<algorithm>头文件中。
逐个处理算法:for_each函数。该函数对迭代器区间的每个元素,执行单参数函数对象定义的操作。例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void print(int x) {
cout << x << " ";
}
int main(void) {
vector<int> v;
for(int i = 0; i < 10; i++) {
v.push_back(i * 2);
}
for_each(v.begin(), v.end(), print);
return 0;
}
结果为0 2 4 6 8 10 12 14 16 18.
元素查找算法:find函数。该函数用于查找等于某值的元素。如果迭代器i所指的元素满足*i == value,则返回迭代器i。未找到满足条件的元素,返回last。只要找到第一个满足条件的元素就返回迭代器位置,不再继续查找。例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v;
for(int i = 0; i < 10; i++) {
v.push_back(i * 2);
}
vector<int>::iterator iv = find(v.begin(), v.end(), 6);
if(iv == v.end()) {
cout << "Find nothing." << endl;
} else {
cout << "The postion of " << *iv << " is " << iv - v.begin() << endl;
cout << "The previous element of it is " << *(--iv) << endl;
}
return 0;
}
结果为The postion of 6 is 3 \n The previous element of it is 4.
元素查找算法:find_if函数。该函数是find的一个谓词判断版本,查找满足谓词判断函数的元素。例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int divBy3(int x) {
return x % 3 ? 0 : 1;
}
int main(void) {
vector<int> v;
for(int i = 1; i < 10; i++) {
v.push_back(i * 2);
}
vector<int>::iterator iv = find_if(v.begin(), v.end(), divBy3);
if(iv == v.end()) {
cout << "None could be divided by 3 with no remaineder." << endl;
} else {
cout << *iv << " could be divided by 3 with no remainder." << endl;
}
return 0;
}
结果为6 could be divided by 3 with no remainder.
元素查找算法:adjacent_find函数。该函数用于查找相等或满足条件的邻近元素对。它有两个使用原型,一个用于查找相等的两个连续元素,另一个使用二元谓词判断,查找满足条件的邻近元素对。例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int parity_equal(int x, int y) {
return (x - y) % 2 == 0 ? 1 : 0;
}
int main(void) {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(5);
v.push_back(5);
v.push_back(7);
vector<int>::iterator iv = adjacent_find(v.begin(), v.end());
if(iv != v.end()) {
cout << "There are two equal elements." << endl;
cout << "It is " << *iv << endl;
}
iv = adjacent_find(v.begin(), v.end(), parity_equal);
if(iv != v.end()) {
cout << "There are two parity euqal elements." << endl;
cout << "They are " << *iv << " and ";
iv++;
cout << *iv << endl;
}
return 0;
}
结果为
There are two equal elements.\n
It is 5\n
There are two parity euqal elements.\n
They are 3 and 5.
元素查找算法:find_first_of函数。该函数用于查找某个范围之内的元素。它有两个使用原型,一个是相等,另一个是二元谓词判断。元素找到则返回迭代器,否则返回末位置。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(2);
v.push_back(3);
v.push_back(5);
v.push_back(5);
v.push_back(7);
vector<int> v2;
v2.push_back(3);
v2.push_back(3);
v2.push_back(5);
vector<int>::iterator iv = find_first_of(v.begin(), v.end(), v2.begin(), v2.end());
cout << "The position of the first equal element is " << iv - v.begin() << endl;
return 0;
}
结果为The position of the first equal element is 3.
元素统计算法:count函数。该函数用于计算容器中某个给定值的出现次数。它有两个使用原型,区别在于计数是直接返回还是引用返回。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v;
for(int i = 0; i < 17; i++) {
v.push_back(i % 6);
}
int num = count(v.begin(), v.end(), 5);
cout << "The number of 5 is " << num << endl;
return 0;
}
结果为The number of 5 is 2.
元素统计算法:count_if函数。该函数使用谓词判断函数,统计迭代器区间上满足条件的元素个数。它有两个使用原型,区别在与计数是直接返回还是引用返回。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int greaterThan10(int x) {
return x > 10 ? 1 : 0;
}
int main(void) {
vector<int> v;
for(int i = 0; i < 17; i++) {
v.push_back(i);
}
int num = count_if(v.begin(), v.end(), greaterThan10);
cout << "The number of the figure that greater than 10 is " << num << endl;
return 0;
}
结果为The number of the figure that greater than 10 is 6.
序列匹配算法:mismatch函数。该函数用于比较两个序列,找出首个不匹配元素的位置。它有两个使用原型,分别为不相等和不满足二元谓词条件。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v1, v2;
v1.push_back(3);
v1.push_back(5);
v1.push_back(5);
v2.push_back(3);
v2.push_back(5);
v2.push_back(7);
pair<vector<int>::iterator, vector<int>::iterator> result = mismatch(v1.begin(), v1.end(), v2.begin());
if(result.first == v1.end() && result.second == v2.end()) {
cout << "v1 is same as v2." << endl;
} else {
cout << "The dismatching figure are "
<< *(result.first) << " and "
<< *(result.second) << endl;
}
return 0;
}
结果为The dismatching figure are 5 and 7.
序列匹配算法:equal函数。该函数逐一比较两个序列的元素是否相等,返回值为true/false,不返回迭代器值。它有两个使用原型,分别为元素相等和二元谓词判断条件。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int absEqual(int x, int y) {
//return (x == abs(y) || y == abs(x)) ? 1 : 0;
return abs(x) == abs(y) ? 1 : 0;
}
int main(void) {
vector<int> v1, v2;
v1.push_back(3);
v1.push_back(5);
v1.push_back(5);
v2.push_back(3);
v2.push_back(5);
v2.push_back(-5);
if(equal(v1.begin(), v1.end(), v2.begin(), absEqual)) {
cout << "The elements of v1 and v2 are equal in abosolute value." << endl;
} else {
cout << "The elements of v1 and v2 are not equal in abosolute value." << endl;
}
return 0;
}
结果为The elements of v1 and v2 are equal in abosolute value.
子序列搜索算法:search函数。该函数在一个序列中搜索与另一序列匹配的子序列。它有两个使用原型,分别为完全匹配和二元谓词判断。匹配成功则返回子序列的首个元素的迭代器值。search函数与find_first_of函数形似,但不相同。search找的是一块相同的区域,要求这块区域与后面列表的元素及其顺序相同;find_first_of找的是一个元素,只要这个元素是后面一个列表的任意一个就行。
#include <iostream>
#include <algorithm>
#include <vector>
int main(void) {
vector<int> v1, v2;
v1.push_back(1);
v1.push_back(4);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
vector<int>::iterator ivSearch, ivFind;
ivSearch = search(v1.begin(), v1.end(), v2.begin(), v2.end());
ivFind = find_first_of(v1.begin(), v1.end(), v2.begin(), v2.end());
cout << "Position of search: " << ivSearch - v1.begin() << endl;
cout << "Position of find_first_of: " << ivFind - v1.begin() << endl;
return 0;
}
结果为Position of search: 2\nPosition of find_first_of: 1.
子序列搜索算法:search_n函数。该函数用于搜索序列中是否有一系列元素值均为某个给定值的子序列。它有两个使用原型,分别为值相等和满足谓词判断条件。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v;
v.push_back(3);
v.push_back(8);
v.push_back(8);
v.push_back(8);
v.push_back(4);
vector<int>::iterator iv = search_n(v.begin(), v.end(), 3, 8);
if(iv == v.end()) {
cout << "There are no three consecutive 8." << endl;
} else {
cout << "Three consecutive 8 is founded." << endl;
}
return 0;
}
结果为Three consecutive 8 is founded.
子序列搜索算法:find_end函数。该函数用于在一个序列中搜索出最后一个与另一序列匹配的子序列。用search函数作用相似,方向相反。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> v, v2;
v.push_back(1);
v.push_back(3);
v.push_back(5);
v.push_back(3);
v.push_back(5);
v.push_back(7);
v2.push_back(3);
v2.push_back(5);
vector<int>::iterator iv = find_end(v.begin(), v.end(), v2.begin(), v2.end());
if(iv != v.end()) {
cout << "The position of last matching subsequence is " << iv - v.begin() << endl;
}
return 0;
}
结果为The position of last matching subsequence is 3.