继续上一个博文的内容:

5、使用泛型算法

使用泛型算法,需要包含的头文件是:

#include<algorithm>
  1. ​find()​​函数用于查询无序序列中是否存在某值,存在则返回一个iterator指向该值,否则返回一个iterator指向end。
  2. ​binary_search()​​用于有序集合的搜索。成功返回true,否则返回false。
  3. ​count()​​返回序列中数值相等的元素的个数。
  4. ​search()​​是用来比对某个容器内是否存在某个子序列,存在子序列,返回子序列初始值的iterator位置,否则返回end位置。

  对于Fibonacci数列是递增有序的序列​​binary_search()​​是最佳选择。

#include<algorithm>
bool is_elem(vector<int> &vec, int elem)
{
// 调用binary_search()之前,必须先要检查是否需要扩展vector
return binary_serach(vec.begin(), vec.end(), elem);
}

  在执行前,首先需要确保elem在数列中。方法是拿elem与数组中的最大值进行比较,如果elem比较大,就要扩展数列,直到数列中的最大值大于等于elem为止。使用​​max_element()​​函数可以返回数列中的最大值。

#include<algorithm>
// 前置声明
extern bool grow_vec(vector<int>& ,int );

bool is_elem(vector<int> &vec, int elem)
{
int max_elem = max_element(vec.begin(), vec.end());
if(max_elem < elem)
return grow_vec(vec, elem);
if(max_elem == elem)
return true;
return binary_search(vec.begin(), vec.end(), elem);
}

  上述中的​​grow_vec()​​函数会将数列中的元素逐一添加到数组中,直到数组中的最大值等于elem,返回true,否则返回false。

  当然,对于本题的情景,完全没必要用​​max_element()​​函数返回最大值,由于是递增数组,数组中的最大值一定在数值中的最后一位,除非是空数组。

int max_elem = vec.empty() ? 0 : vec[vec.size() - 1];

  ​​binary_search()​​​函数需要数组是有序的,如果担心数组无序,可先对其进行排序,使用​​sort()​​函数。

vector<int> itemp(vec.size());
copy(vec.begin(), vec.end(), itemp.begin());

sort(itemp.begin(), itemp.end());
return binary_search(itemp.begin(), itemp.end(), elem);

6、如何设计一个泛型算法

  有如下情景:给定一个整型vector,返回一个新的vector,其中内含原vector中小于10的元素,首先缺乏弹性的写法是这样的:

vector<int> less_than_10(const vector<int> &vec)
{
vector<int> nvec;
for(int ix = 0; ix < vec.size(); ++ix)
if(vec[ix] < 10)
nvec.push_back(vec[ix]);
return nvec;
}

  如果要将比较的值参数化,就需要在函数的参数列表表明一个上限值即可。

vector<int> less_than(const vector<int> &vec, int less_than_val);

  下一步是如何将“比较操作”参数化?

  可以使用函数调用的方法取代​​less_than​​​来解决。引入第三个参数pred,用它来指定函数指针,其参数列表有两个参数,返回值为bool。所以​​less_than()​​​函数名不再适用,取名为​​filter()​​。

vector<int> filter(const vector<int> &vec, int filter_value, bool (*pred)(int , int ));

  我们同时定义了许多可以传给​​filter()​​的关系(relational)比较函数

bool less_than(int val1, int val2)
{
return val1 < val2 ? true : false;
}

bool greater_than(int val1, int val2)
{
return val1 > val2 ? true : false;
}

  当调用​​filter()​​函数时,用户可以传入上述函数,不足就是这个函数必须返回bool型且参数只能是两个,下述是该算法的使用方式。

vector<int> big_vec;
int value;
vector<int> It_10 = filter(big_vec, value, less_than);

  下述是实现​​filter()​​的代码:

vector<int> filter_ver1(const vector<int> &vec, int filter_value, bool (*pred)(int, int ))
{
vector<int> nvec;
for(int ix = 0; ix < vec.size(); ++ix)
if(pred(vec[ix], filter_value))
nevc.push_back(vec[ix]);
return nvec;
}

  上述代码使用for循环赋值,完全可以由泛型算法​​find_if()​​​来替代。先从​​find()​​函数开始说起,找出每个等于val的元素:

int count_occurs(const vector<int> &vec, int val)
{
vector<int>::const_iterator iter = vec.begin();
int occurs_count = 0;
while((iter = find(vec.begin(), vec.end(), val)) != vec.end())
{
++occurs_count;
++iter;// 为了指向下一个元素,不加这句话的话 就是死循环
}
return occurs_count;
}

函数对象(function object): 是某种class的实例对象,这类class对function call运算符做了函数重载,函数对象可以被当做是一般的函数使用,函数对象实现了我们原本可能以独立函数加以定义的事物

  欲使用事先定义的function object,首先得包含相关头文件:

#include<functional>

sort(vec,begin(), vec.end(), greater<int>());

binary_seacrch(vec,begin(), vec.end(), elem, greater<int>());

函数对象适配器(function object adapter): 是将函数对象的参数绑定至某个特定值。例如,​​less<type>​​​期望外界传入两个值,每个值都必须和用户指定的元素进行比较。理想情况下,将​​less<type>​​转化为一个一元运算符。这可以通过第二个参数绑定(bind)至用户指定的数值完成。这样​​less<type>​​会将每个元素拿出来一一与用户指定的值比较。

  ​​bind1st​​​会将指定值绑定至第一操作数,​​bind2nd​​会将指定值绑定至第二操作数。

vector<int> filter(const vector<int> &vec, int val, less<int> &It)
{
vector<int> nvec;
vector<int>::const_iterator iter = vec.begin();
while((iter = find_if(vec.begin(), vec.end(), bind2nd(It, val))) != vec.end())
{
nvec.push_back(*iter);
iter+;
}
return nvec;
}

  下面,如何消除​​filter()​​函数和vector的关系,使得函数具有更高的泛型:

template<typename InputIterator, typename OutputIterator, typename ElemType, typename Comp>
OutputIterator filter(InputIterator first, InputIterator last, OutputIterator at, const ElemType &val, Comp pred)
{
while((first = find_if(first, last, bind2nd(pred, val))) != last)
{
cout << "found value: " << *first << endl;
*at++ = *first++;
}
return at;
}

  下一篇博文继续讲述泛型编程风格这一章节的后序内容,map 和 set 的用法, to be contiuned…