标准C++库里面提供了很多的通用算法,比如查找,排序等等, 这些算法完全建立在STL的基础上,是最先进算法的优良实现,有极好的性能, 和C库里的算法相比,一点也不逊色.
通常这些算法是对标准容器的操作
,
比如
vector, list, map
等等
,
在用的时候非常灵活
,
所有的算法包含在
<algorithm>
里
,
下面我会做一些典型的介绍
.
首先是一段不用任何算法的代码
:
int f(vector<int>& c)
{
vector<int>::iterator it=c.begin(),end=c.end();
while(it!=end)
{
if(*it<7)
return*it;
}
return 0;
}
{
vector<int>::iterator it=c.begin(),end=c.end();
while(it!=end)
{
if(*it<7)
return*it;
}
return 0;
}
下面引入第一个算法
:find_if
bool less_than_7(int v)
{
return v<7;
}
{
return v<7;
}
int f2(vector<int>& c)
{
vector<int>::iterator it=find_if(c.begin(),c.end(),less_than_7);
if(it!=c.end())
return *it;
return 0;
}
{
vector<int>::iterator it=find_if(c.begin(),c.end(),less_than_7);
if(it!=c.end())
return *it;
return 0;
}
less_than_7
是我们编写的一个函数
,
用于算法
find_if.
算法的作用是找到
vector
里所有的元素小于
7
的序列
.
请看另外一个实现相同功能的方式
:
函数对象
.
函数对象
,
如果一个类具有应用运算符
,
我们就称其为函数对象
.
class less_than
{
public:
less_than(int i=0):v(i){}
bool operator()(int x){return x<v;}
private:
int v;
};
{
public:
less_than(int i=0):v(i){}
bool operator()(int x){return x<v;}
private:
int v;
};
int f3(vector<int>& c)
{
less_than les(7);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
if(it!=c.end())
return *it;
return 0;
}
{
less_than les(7);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
if(it!=c.end())
return *it;
return 0;
}
这里我们换成一个类
,
比较的值可以传进类里
,
实现了更大的灵活性
.
进一步
,
我们把比较的值的类型抽象
,
把函数对象变为模板
:
template<class T>
class less_than
{
public:
less_than(T i=0):v(i){}
bool operator()(T x){return x<v;}
private:
T v;
};
class less_than
{
public:
less_than(T i=0):v(i){}
bool operator()(T x){return x<v;}
private:
T v;
};
int f3(vector<int>& c)
{
less_than<int> les(7);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
if(it!=c.end())
return *it;
return 0;
}
{
less_than<int> les(7);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
if(it!=c.end())
return *it;
return 0;
}
像
less_than
这样的对象我们经常用到
,
那么有没有库里实现好的
,
我们直接拿来用的呢
?
有的
!
下面我们介绍基本的谓词
:
谓词就是返回
bool
的函数或函数对象
.
void f4(vector<int>& vi,list<int>& li)
{
typedef list<int>::iterator LI;
typedef vector<int>::iterator VI;
pair<VI,LI> pl=mismatch(vi.begin(),vi.end(),li.begin(),greater_equal<int>());
...
}
{
typedef list<int>::iterator LI;
typedef vector<int>::iterator VI;
pair<VI,LI> pl=mismatch(vi.begin(),vi.end(),li.begin(),greater_equal<int>());
...
}
greater_equal
就是库里的一个常用谓词
: return arg1>=arg2, mismatch
也是库里的算法
,
意思是找到两个序列相异的第一个元素
.
在这里就是寻找
vector
中小于在
list
中对应元素的第一个元素
.
在
<functional>
里
,
标准库里提供了一些常用的谓词
,
如
:equal_to, less, greater
等
,
当然我们也可以开发自己的谓词
,
比如下面一个
:
Class MyEqual:public unary_function<Teacher,bool>{
String s;
Public:
MyEqual(const string& str):s(str) {}
Bool operator() (const Teacher & t) const {return t.name==s;}
};
…
List<Teacher> li;
List<Teacher>::iterator it=find_if(li.begin(),li.end(),MyEqual(“
张三
”));
上面代码的功能是找到教师序列里名字为
”
张三
”
的老师
.
其中
unary_function
是所有一元谓词对象的基类
.
约束器
,
通过将一个参数约束到某个值
,
我们可以将两个参数的函数对象当作一个参数的函数对象使用
.
对于上面的例子
:
less_than les(7);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
vector<int>::iterator it=find_if(c.begin(),c.end(),les);
less_than
是我们额外写的一个类
,
如果我们不想写自己的类
,
而直接利用库里的谓词
less,
这样岂不是更好吗
?
约束器就是满足这种需求
:
vector<int>::iterator it=find_if(c.begin(),c.end(),bind2nd(less<int>(),7);
bind2nd
就是一个常用的约束器
,
它把二元谓词
less
和常数
7
出发建立起一元谓词
”
小于
7”.
成员函数适配器
,
使成员函数可以被用做算法参数
.
void draw_all(list<Shape*>& lsp)
{
for_each(lsp.begin(),lsp.end(),mem_fun(&Shape::draw));
}
这里是通过指针调用成员函数的
,
如果需要参数
,
那么我们就可以用到前面讲的
bind2nd
了
:
void draw_all(list<Shape*>& lsp,int angle)
{
for_each(lsp.begin(),lsp.end(),bind2nd(mem_fun(&Shape::rotate),angle));
}
函数指针适配器
,
使函数适指针可以用作算法参数
.
void draw(const int angle);
void draw_all(list<Shape*>& lsp)
{
for_each(lsp.begin(),lsp.end(),bind2nd(ptr_fun(draw),30));
}
否定器
,
描述某个谓词的否定
.
void f7(vector<int>& vi,list<int> li)
{
pi=mismatch(vi.begin(),vi.end(),li.begin(),not2(less<int>()));
}
谓词
,
约束器
,
适配器和否定器都定义在
<functional>
里
.
有些一下子看起来比较生僻
,
这是一个习惯问题
,
你熟悉了
,
也就觉得很自然了
.
而且这些都在标准库里
,
可移植性都很高
.
这里只是介绍一些基本的入门知识
,
通过这些初步的代码
,
我们知道算法可以节省我们大量的精力
,
避免我们为这些常见的算法一再的去重复劳动
,
而且代码更精简
.