泛型算法就是一种对其所作用的数据结构做尽可能少的约束的方式表达的算法
以一个简单的查找整数数组中的第一个等于某个值的元素为例
/*
在这个例子中,我们做了四个约束:
分别是查找的类型是int值
我们对int数组进行查找
我们预先已经知道了元素的书目
我们已经预先知道了第一个元素的地址
这些约束条件降低了程序的通用性 为了提高程序的通用性 必须想办法去掉这些约束条件
*/
const int* find1(const int *array ,int n,int x)
{
const int *p =array;
for(int i = 0;i<n;i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
(1)去掉查找数据类型限制条件
/*
最容易想到的办法就是用模板来代替原来有的int类型的数据 重点做以下说明
首先 const int* 替换成了 T* 这样 T*可以完全替代const int *的功能
其次 int x 替换成了const T &x 这是因为很多时候 变量x是不可以复制 或者复制的代价太大的情况
处理这些情况 一方面可以避免错误 另一个方面也可以提高通用性和效率
*/
template<typename T>
T* find2(T* array ,int n ,const T & x)
{
T *p = array;
for(int i =0;i <n;i++)
{
if(*p==x)
return p;
++p;
}
return 0;
}
(2)去掉必须知道元素个数的限制
/*
这个位置的问题是我们使用了两个指针 一个是元素起始位置 另一个是元素结束位置的下一个位置的指针 为什么这样做呢,而不是指向最后一个元素呢 因为指向最后一个元素是非常危险的事情 最后一个元素可能并不存在,根本就没有任何元素 这种情况下,指针会指向第一个元素之前,这种情况可能导致错误
*/
template<typename T>
T* find3(T* array ,T* beyond, const T& x)
{
T* p = array;
while(p != beyond)
{
if(*p==x)
{
return p;
}
++p;
}
return 0;
}
(3)去掉返回值的限制 使得函数的实现更简单
/*
这段代码实现了指定元素的查找 查找到了就会返回当前元素的指针 否则就会返回为空,这样就取消掉了元素类型的限制 使代码变得非常简洁
*/
template<typename T>
T* find4(T* array ,T*beyond ,const T &x)
{
T* p =array;
while(p != beyond&& *p !=x)
{
++p;
}
return p;
}
进行上述操作后我们发现 我们依旧依赖于对指针的操作
//泛型算法是一种对它所作用的数据结构进行尽可能少的做约束的方式表达的算法
/*
指针在finf4的作用有如下几个 可以把指针作为参数 并把他们作为结果返回 也可以
比较指针想不想等 可以解除引用指针 以便得到指针所指向的变量的值 可以递增指针
以实现指针的移动 加入我们用 P 来代替T* 就可以取消对指针的依赖
*/
template<typename P,typename T>
P find5(P start, P beyond,const T& x)
{
while(start !=beyond&&*start !=x)
++start;
return start;
}
/*
经过上述的处理 ,fund5已经能够丢掉前文所述的四个约束条件,也不要求p是指针类型
进一步的我们可以把程序修改成更加通用的表达
*/
template<typename S, typename T>
S find5(S a,S b,const T &x)
{
S s =a;
while(s !=b&& *s !=x)
{
++s;
}
return s;
}
/*
测试程序
*/
int main(int argc, char const *argv[])
{
cout<<"测试程序"<<endl;
int x[100];
vector<int> v;
for(int i =0;i<100;i++)
{
x[i]= i+1;
v.push_back(i+1);
}
cout<<*find5(v.begin(),v.end(),98);
cout<<"************"<<endl;
system("pause");
return 0;
}
/*
[Running] cd "d:\MyWorkSpace\VsCode\Test\" && g++ test.cpp -o test && "d:\MyWorkSpace\VsCode\Test\"test
测试程序
98************
*/
下面考虑对非数组的查找
/*
有一个包含String元素的链表 要如何利用上述已经定义的函数来
查找单项链表中的某个元素是否存在
*/
struct Node
{
string value;
Node *next;
};
Node *listfind(Node *p ,const string &x)
{
while(p&&*p!= x)
p = p->next;
return p;
}
/*
要实现链表的操作 我们必须要定义一个辅助的类 用以进行几个基本操作 *运算 !=运算 ++运算 等等
辅助类的建立如下
*/
class Nodep
{
public:
Nodep(Node *p): pt(p){}
string & operator*()
{
return pt->value;
}
void operator++()
{
pt = pt->next;
}
friend int operator!=(const Nodep& p, const Nodep &q)//类外面要使用这个函数
{
return p.pt != q.pt;
}
operator Node*()//转换运算符,Nodep转换到Node*类型
{
return pt;
}
private:
Node *pt;
};
辅助类完成之后 就可以做测试了
#include<iostream>
#include"test.h"
#include<vector>
#include<string>
#include "typedef.h"
using namespace std;
//接口模板的实现
int main(int argc, char const *argv[])
{
cout<<"测试程序"<<endl;
Node n1;
Node n2;
Node n3;
n1.next = &n2;
n1.value ="100";
n2.next =&n3;
n2.value ="101";
n3.next =NULL;
n3.value="102";
Node *p =&n1;
cout<< *find5(Nodep(p),Nodep(0),"100");
cout<<"************"<<endl;
system("pause");
return 0;
}
/*
[Running] cd "d:\MyWorkSpace\VsCode\Test\" && g++ test.cpp -o test && "d:\MyWorkSpace\VsCode\Test\"test
测试程序
100************
*/