将一个叙述完整的算法转化为程序代码,不是什么难事。然而,如何将算法独立与其所处理的数据结构之外,不受数据结构的羁绊呢?换个说法,如何将我们所写的程序算法适用于任何(或者大部分)未知的数据结构(比如array,vector,list等)呢?

  关键在于,只要把操作对象的型别加以抽象化,把操作对象的标示法和区间目标的移动行为抽象化,整个算法也就在一个抽象层面上工作了。整个过程称为算法的泛型化(generalized),简称泛化。

  以简单的循序查找为例,编写find()函数,在array中寻找特定值。面对整数array,写出如下程序:

int* find(int* arrayHead, int arraySize, int value)
{
int i=;
for (; i<arraySize; ++i)
{
if (arrayHead[i] == value)
{
break;
}
} return &(arrayHead[i]);
}

  该函数在某个区间内查找value。返回的是一个指针,指向它所找到的第一个元素;如果没有找到,就返回最后一个元素的下一位置(地址)。

  “最后一个元素的下一位置”称为end。为什么不返回null?因为,end指针可以对其他种类的容器带来泛型效果,这是null所无法达到的。事实上一个指向array元素的指针,不但可以指向array内部任何位置,也可以指向array尾端以外的任何位置。只不过当指针指向array尾端以外的位置时,它只能用来与其他array指针相比较,不能提领(dereference)其值。

    const int arraySize = ;
int ia[arraySize] = {, , , , , , };
int* end = ia + arraySize; int * ip = find(ia, sizeof(ia)/sizeof(int), );
if (ip == end)
{
cout<<"4 not found"<<endl;
}
else
{
cout<<"4 found. "<<*ip<<endl;
}

  上述find()函数写法暴露了太多的实现细节(例如arraySize),为了让find()适用于所有类型的容器,其操作应该更抽象化些。让find()接受两个指针作为参数,标示一个操作区间:

int* find(int* begin, int*end, int value)
{
while(begin !=end && *begin != value)
++begin; return begin;
}

  由于find()函数之内并无任何操作是针对特定整数array而发的,所以我们可以把它改成一个template:

template<typename T>
T* find(T* begin, T* end, const T& value)
{
// 注意,以下用到了operator!=, operator*, operator++
while (begin != end && *begin != value)
++begin; // 注意,以下返回操作用会引发copy行为
return begin;
}

  注意数值传递由pass by value改为pass by reference const, 因为value的型别可为任意,对象一大,传递成本便会提升。

  在上述代码中,传入的指针必须支持以下四种操作行为:

  • inequality 判断不相等
  • dereferencelm 提领
  • prefix increment 前置式递增
  • copy 复制

  上述操作符可以被重载(overload),find()函数就可以从原声(native)指针的思想框框中跳脱出来。我们可以设计一个class,拥有原生指针的行为,这就是迭代器(iterator):

template<typename Iterator, typename T>
Iterator find(Iterator begin, Iterator end, const T& value)
{
while(begin != end && *begin != value)
++begin; return begin;
}

  这便是完全泛型化的find()函数。

算法的泛化过程(摘自《STL源码剖析》)的更多相关文章

  1. 【STL 源码剖析】浅谈 STL 迭代器与 traits 编程技法

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub : https://github.com/rongweihe/Mor ...

  2. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  3. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  4. STL"源码"剖析

    STL"源码"剖析-重点知识总结   STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...

  5. 《STL源码剖析》读书笔记

    转载:https://www.cnblogs.com/xiaoyi115/p/3721922.html 直接逼入正题. Standard Template Library简称STL.STL可分为容器( ...

  6. 通读《STL源码剖析》之后的一点读书笔记

    直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adap ...

  7. (原创滴~)STL源码剖析读书总结1——GP和内存管理

    读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...

  8. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  9. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  10. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...

随机推荐

  1. CSS实现文字两端对齐

    最近的项目遇到了这样的需求:(要求标题部分不管文字多少,都必须两端对齐) 如下图: 当时也没有多想直接使用‘ ’进行代替,毕竟产品同学想快一点看到效果,不敢怠慢!不过到第二个页面就傻眼了. 如图: 这 ...

  2. FATAL bad indentation of a mapping entry at line 83, column 3: branch: master 已解决;

    部署hexo 时候,修改完_config.yml  文件后更新报错如下,问题解决: FATAL bad indentation of a mapping entry at line 83, colum ...

  3. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

  4. Javascript获取For循环所用时间

    第一种: let tOne = new Date().getTime(); let n = new Date(); let hour = n.getHours() < 10 ? "0& ...

  5. javascript实现数据结构: 树和森林

    树的3种常用链表结构 1 双亲表示法(顺序存储结构) 优点:parent(tree, x)操作可以在常量时间内实现 缺点:求结点的孩子时需要遍历整个结构 用一组连续的存储空间来存储树的结点,同时在每个 ...

  6. CentOS7运维管理笔记(12)----修改主机名

    CentOS修改主机名 CentOS7和CentOS6.5 修改主机名的方法略有不同. 通过 hostname 命令可以查看当前的主机名. 1. 临时修改主机名 通过 'hostname 新的主机名' ...

  7. 对数损失函数(Logarithmic Loss Function)的原理和 Python 实现

    原理 对数损失, 即对数似然损失(Log-likelihood Loss), 也称逻辑斯谛回归损失(Logistic Loss)或交叉熵损失(cross-entropy Loss), 是在概率估计上定 ...

  8. Sql Server关于日期查询时,如果表中日期到具体某个时间

    1.如果查询日期参数为'2017/02/21',而数据库表中的字段为'2017/02/21 12:34:16.963',则需要格式化一下日期才能查询出来,如下 select * from table ...

  9. 变换CALayer锚点实现模拟时钟的动画

    变换CALayer锚点实现模拟时钟的动画 变换锚点得需要一点理论知识,看下图就能明白:). https://developer.apple.com/library/ios/documentation/ ...

  10. 准备你的 In-app Billing 程序

    准备好你的内购应用 在开始使用 In-app Billing 服务之前,你需要先把包含 In-app Billing Version 3 API 的库添加到你的Android工程中.你还需要设置你的应 ...