Essential C++学习笔记-----第三章 泛型编程

1.何谓泛型算法

         所谓泛型算法,提供了许多可施于容器类及数组上的操作行为,之所以将这些算法称为泛型,是因为这些操作与它们所要作用于的对像的数据类型(如,int,double等)无关,并且与

容器类型(如,vector,list,map等)也无关.

1.1如何实现与作用对像的数据型别(类型)无关

        这正是应用了前面第二章中我们学到的模板函数来实现的.

        例如,我们要实现一个查打算法find(),用以在vector内查找目标值,如果查到就返回指向其的指针或返回其地址,如果找不到就返回0.而vector内无素是什么类型并不确定,可以是

int型,也可以是double型,或者是string等.

        对于这个问题,想要实现的话当然必须要求元素无论是什么类型,但这些类型应当都具有equality(==)运算.

        下面就是实现:

template<typename elemType>

elemType *find(vector<elemType> &vec,elemType &e)

{

        int i;

        for(i=0;i<vec.size();i++)

             if(vec[i]==e) return &vec[i]; //这的&号不同于形参中的&,形参中是表引用,传址,而这是表取址

        return 0;

}

这个实现很好理解,既然类型不定,那么我们就通过template<typename elemType>这句话将类型假定为elemType,当然也可取其他名称,反正都只是起指代作用.

但是这些类型必须具有equality(==)运算.

1.2如何实现与容器类型不相关

         这就要求我们不要直接在容器上操作,就是说我们编的函数形参不能是容器类型,例如上面第一个参数就是vector类型,在这里是行不通的.取而代之的是我们只需要

把所以操作对像的区间参进去,至于这段区间内元素之间关系是什么样的,我们并不用去理它,这些交给底层去做.

        那么怎么传区间呢,第一种想法是传首址和长度.第二种想法是传两个指针分别指向首尾元素.

1.2.1传首址和长度

template<typename elemType>

elemType *find(elemType *array,int size,elemType value)

{

      int i;

      if(!array||size<1) return 0;

      for(i=0;i<size;i++)

          if(array[i]==value) return &array[i];

       return 0;

}

1.2.2传首尾元素指针

上面第一种做法还是不彻底,还是有数组(array)的影子.假如我们设两个指针first,last分别指向首元素和最后个元素的下一位置,这样就不用理会是什么容器类型了.

template<typename elemType>

elemType *find(elemType *first,elemType *last,elemType &value)

{

     if(!first||!last) return 0;

     for(;first!=last;first++)

         if(*first==value) return first;

      return 0;

}

注意,last是指向最后个元素的下一个位置的,只起到哨兵角色,并不能对之进行读取操作,否则会越界.

 

2.泛型指针Iterators

        注意到了没有,上面在实现操作与容器类型无关时,无论是array还是vector都是顺序存储的,我们在for循环迭代中都是用++的形式进行取下一个元素.

但如果容器换成list呢,它是链式存储的.难不成又得专门写一个对list的函数.

        其实,我们可以在1.2.2的基础上进一步泛化抽像.1.2.2中的first指针和last指针,虽然实现了数据类型无关和一定程度上的容器无关性,注意只是一定程度,比如还不能

完全实现存储结构的无关性,上面1.2.2只适合于顺序存储.我们可以对这对指针进行抽像泛化,变成泛化指针Iterators class,即不考虑它的存储结构,到于怎么取下一个无素地址,我们交给iterators class内部中的内联函数去实现.对于list iterator 来说,其递增到下一个元素可以通过沿着前进指针实现,而vector iterator取下一个元素,可以将当前地址加上一个数据类型大小得到.

 

2.1定义一个iterator对象

      vector<string>:: iterator iter;//这样就定义了一个iterator对象iter

      vector <string>::表示iterator是vector内的嵌套定义

2.2获得一个iterator对象

     每个容器都提供了begin()函数,这个函数返回值是iterator对象,用以指向容器的第一个元素,也同时提供了end()函数,返回的iterator对象是指向最后个元素的下一位置.

     int ia[5]={1,2,2,3,5};

    vector<int> ivec(ia,ia+5);

    vector<int>:: iterator first,last;

   first=ivec.begin();

   last=ivec.end();

 对find()函数进行改造

template<typename iteratorType, typename elemType>

iteratorType find(iteratorType first,iteratorType last,elemType value)

{

      for(;first!=last;++first)

          if(value==*first)

              return first;

    return last;

}

 

2.3所有容器及string类都有的操作

equality(==)和inequality(!=)运算符;

赋值运算符(=);将某个容器复制给另一个容器

empty();

size();

clear();清空所有元素

begin();

end();

insert();

erase();删除元素,抹除操作

 

 

3.序列式容器

主要有三种:

vector向量:顺序存储

list:双链式存储

deque(读作deck)即double-ended queue双端队列,是一种具有队列和栈性质的数据结构,与vector相同,都是顺序存储,但与vector相比,其插入删除操作限定在两端执行.

 

 

使用序列式容器,必须含入相关的头文件

#include<vector>

#include<list>

#include<deque>

 

3.1定义序列式容器对象

有五种方式

3.1.1定义产生空容器

vector<int> ivec;

3.1.2 产生特定大小容器,每个元素都被默认初始化了

vector<int > ivec(1024);

3.1.3指定大小,并且为每个元素指定初始值

vector <int > ivec(10,1);

3.1.4 指定区间,通常用一对iterators 来分别指定首址和最后个元素的下一个位置

int ia[5]={0,12,1,2,5};

vector<int> ivec(ia,ia+5);

3.1.5 复制容器

vector<int> ivec1(10,1);

vector<int> ivec2(ivec1);

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值