泛型算法的设计(1)

泛型算法的设计(1)
前言:
泛型算法独立于操作的容器且与要操作的元素类型无关,达到了函数弹性设计的最大化,下面我们一步步的实现一个泛型算法;

1.有一天,老板交给你一个任务,要你编程完成如下工作,给定一个存储整数的vector,及一个整数,如果此值存在于vector内,我们必须返回一个指针指向该值;反之则返回0,表示此值不在vector内;
int find(const vector<int> &vec, int value)
{
    for(int ix=0;ix!=vec.size(); ++ix)
       if(vec[ix]==value)
          return &vec[ix];
    return 0;
}

注:
当我们实现一个搜索函数且用指针为返回值时,我们通常返回0值来标识搜索失败;

任务完成的如此顺利,以至于你有些沾沾自喜,过了一段时间老板让你在存储字符串的vector中查找一字符串,这是你开始反思之前那段代码,发现他解决的问题很狭隘,就想从新设计一个新的函数,不仅可以处理整数,也可以处理任何型别;


2.将find()用function template的形式呈现
template <typename elemtype>
elemtype* find(const vector<elemtype> &vec, elemtype value)
{
    for(int ix=0; ix!=vec.size(); ++ix)
       if(vec[ix]==value)
          return &vec[ix];
    return 0;
}

大功告成,欣喜之余,新任务也接踵而来,这次需要处理在array中查找一元素,这样需要编写一函数可以同时处理vector,array的元素,用重载固然可行,但略显笨拙;
这次问题有点棘手,我们的设计思想是将元素传入函数,但不指明vector或array,即设法使函数独立于要操作的容器,下面我们一一着手解决;
3.在不指明array的情形下将元素传入find();
  我们的设计思路是传递两个指针,第一个指针是要处理的第一个元素,最后一个指针是要处理的最后一个元素的下一个地址(充当哨兵的作用);
template <typename elemtype>
elemtype* find(const elemtype *first, const elemtype *last, elemtype value)
{
    if(!first||!last)
      return 0;
    for(;first!=last;++first)
        if(*first==value)
           return first;
    return 0;
}
注:
当我们提领指针时,一定要确保其值并非为0;
4.用同样的思路对vector中的元素进行超找;
  因为vector可以为空的,而当我们对一个空的vector进行&vec[vec.size()]运算时会产生一个运行时错误,故我们在调用函数前要先确定函数不为空,即每次调用find()需先判断:
if(!vec.empty())
  ...
但这种函数对调用者是不友好的,因此我们定义两个内联函数begin(),end()分别返回vector的第一个元素的地址和最后一个元素的下一个地址,同时检测vector是否为空;
template <typename elemtype>
inline elemtype* begin(const vector<elemtype> &vec)
{
    return vec.empty() ? 0 : &vec[0];
}

template <typename elemtype>
inline end(const vector<elemtype> &vec)
{
    return vec.empty() ? 0 : &vec[vec.size()];
}
以这两个函数为基础,我们可以完成一个看似完美的设计:
find(begin(vec),end(vec),seachvalue);
到这里我们完成一个比较泛型的算法,独立与要处理的元素即可以处理int,string,double...,且一定程度上独立与要操作的容器,即可处理array,vector,开始有人击节相庆

了...
可是我们忽略了支持这个函数正常运行的潜在的限制;
1.指针可以通过算术运算遍历要处理的元素;
2.要处理的元素定义了==操作符;
下面我们对这两个限制条件进行进一步泛化,首先看第一个限制条件,当我们操作list容器时就力不从心了,因为list容器的元素以一组指针互相链接,不能通过++运算遍历,

这样带了的一个问题是,通过array,vector,list指针遍历容器元素的底层运行方式大相径庭,我们解决的思路是:将通过指针遍历容器元素的行为抽象出来,在底层指针之上提供一层抽象机制,

使其对程序员透明,我们通过iterator实现这层抽象;
我们设计一个iterator class提供内建的++,*,==,!=运算符,使其与指针有一样的功能;
最终我们用iterator取代指针且取消原先数组的下表操作改用提领操作,实现一个真正意义上的泛型算法,其独立于操作的容器,独立于操作的元素类型;
template <typename IteratorType, typename elemType>
IteratorType find(IteratorType first, IteratorType last,
                  const elemType value)
{
     for(;first!=last;++first)
        if(*first==value)
          return first;
     return last;
}

总结:
抽象,透明的思想是计算机中一个重要的设计思想,通过不同层次的抽象,为不同层次的用户提供了一个透明的接口,当抽象到最后,面对终端用户时,
提供给普通大众的一个鼠标操作的窗口菜单界面,

迭代器是使用抽象透明设计思想典型例子,在面向程序员的这一层次,迭代器将指针对顺序表及链表的遍历操作抽象出来,供程序员直接通过++,
--,==等指针运算,而不用考虑具体的底层中通过指针超找下一个元素的方式。

转载于:https://www.cnblogs.com/liuhao2638/archive/2012/03/29/2424209.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值