STL实践与分析

--概述、初窥算法【上】

    标准库容器定义的操作很少。并没有给容器加入大量的功能函数。而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是“泛型”的。可作用在不同类型的容器和不同类型的元素上!

    所谓泛型算法:一是由于它们实现共同的操作,所以称之为“算法”;而“泛型”指的是它们可以操作在多种容器类型上——不但可作用于vectorlist这些标准库类型,还可用在内置数组类型、甚至其它类型的序列上,仅仅要自己定义的容器类型仅仅要与标准库兼容,同样可以使用这些泛型算法。

   大多数算法是通过遍历由两个迭代器标记的一段元素来实现其功能。

典型情况下,算法在遍历一段元素范围时,操纵当中的每个元素。算法通过迭代器訪问元素,这些迭代器标记了要遍历的元素范围。

一、概述

    int searchVal = 110;
vector<int>::const_iterator iter = find(ivec.begin(),ivec.end(),searchVal); if (iter != ivec.end())
{
cout << "The value " << *iter << " is present!" << endl;
}
else
{
cout << "The value " << searchVal << " is not present!" << endl;
}

使用两个迭代器和一个值调用find函数,检查两个迭代器实參标记范围内的每个元素。仅仅要找到与给定值相等的元素,find就会返回指向该元素的迭代器。假设没有匹配的元素,find就返回它的第二个迭代器实參,表示查找失败。

由于find运算是基于迭代器的,因此可以在随意容器中使用同样的find函数查找值:

    list<int> iList;
for (list<int>::size_type index = 0; index != 100; ++index)
{
iList.push_back(index);
} int searchVal = 13;
list<int>::const_iterator iter = find(iList.begin(),iList.end(),searchVal); if (iter != iList.end())
{
cout << "The value " << *iter << " is present!" << endl;
}
else
{
cout << "The value " << searchVal << " is not present!" << endl;
}

除了容器类型与对象名称,差点儿没有不论什么改动。

相似的。由于指针的行为与作用在内置数组上的迭代器一样,因此也可以用find来搜索数组:

    int ia[] = {27,210,12,476,109,83};
int searchVal = 109;
int *result = find(ia,ia+sizeof(ia)/sizeof(*ia),searchVal); if (result != ia+sizeof(ia)/sizeof(*ia))
{
cout << "The value " << *result << " is present!" << endl;
}
else
{
cout << "The value " << searchVal << " is not present!" << endl;
}

假设须要一个子区间,则传递给这个子区间的第一个元素以及最后一个元素的下一位置的迭代器或指针。

    int *result = find(ia+2,ia+5,searchVal);

标准算法固有的独立于类型

这样的算法,正如我们所指出的,与容器的类型无关:在前面的描写叙述中,没有不论什么内容依赖于容器类型。这样的算法仅仅在一点上隐式地依赖元素类型:必须可以对元素做比較运算。

该算法的明白要求例如以下:

1)须要某种遍历集合的方式:可以从一个元素向前移到下一个元素。

2)必须可以知道是否到达了集合的末尾。

3)必须可以对容器中的每个元素与被查找的元素进行比較。

4)须要一个类型指出元素在容器中的位置,或者表示找不到该元素。

大多数情况下,每个算法都须要使用(至少)两个迭代器指出该算法操纵的元素范围

第一个迭代器指向第一个元素,而第二个迭代器则指向最后一个元素的下一位置。第二个迭代器所指向的元素【超出末端迭代器】本身不是要操作的元素,而被用作终止遍历的哨兵。

假设元素类型不支持相等(==)操作符,或者打算用不同的測试方法来比較元素,则可使用第二个版本号的 find函数。这个版本号须要一个额外的參数:实现元素比較的函数名字。

这些算法从不使用容器操作,因而事实上现与类型无关,元素的全部訪问和遍历都通过迭代器实现。实际的容器类型未知(甚至所处理的元素是否存储在容器中也是未知的)。

//P338 习题11.1
int main()
{
ifstream inFile("input");
vector<int> iVec;
int val; while (inFile >> val)
{
iVec.push_back(val);
} int searchVal;
while (cin >> searchVal)
{
cout << searchVal << " have present "
<< count(iVec.begin(),iVec.end(),searchVal)
<< " times" << endl;
}
}

//习题11.2
int main()
{
ifstream inFile("input");
list<string> strList;
string val; while (inFile >> val)
{
strList.push_back(val);
} string searchVal;
while (cin >> searchVal)
{
cout << searchVal << " have present "
<< count(strList.begin(),strList.end(),searchVal)
<< " times" << endl;
}
}

【关键概念:算法永不运行容器提供的操作】

泛型算法本身从不运行容器操作,仅仅是单独依赖迭代器和迭代器操作实现。

算法基于迭代器及其操作实现,而并不是基于容器操作

【P338推荐!】

二、初窥算法【上】

使用泛型算法必须包括algorithm头文件:

#include <algorithm>

标准库还定义了一组泛化的算术算法。其命名习惯与泛型算法同样,使用这些算法必须包括numeric头文件:

#include <numeric>

除了少数例外情况,全部算法都在一段范围内的元素上操作,我们将这段范围称为“输出范围”。

带有输入范围參数的算法总是使用头两个形參标记该范围。这两个形參是分别指向要处理的第一个元素和最后一个元素的下一位置的迭代器。

1、仅仅读算法

accumulate的使用:

一个简单的仅仅读算法accumulate,该算法在numeric头文件里定义。

    int sum = accumulate(iVec.begin(),iVec.end(),0);
cout << sum << endl;

将sum设置为 vec的元素之和再加上0。accumulate带有三个形參。

头两个形參指定要累加的元素范围。

第三个形參则是累加的初值。

首先,调用该函数时必须传递一个起始值,否则,accumulate将不知道使用什么起始值。

其次,容器内的元素类型必须与第三个实參的类型匹配,或者可转换为第三个实參的类型。在accumulate内部,第三个实參用作累加的起点;容器内的元素按顺序连续累加到总和之中。

因此,必须可以将元素类型加到总和类型上。

相似的,也可以使用accumulate把string类型的vector容器中的元素连接起来:

string sum = accumulate(strVec.begin(),strVec.end(),string(""));

【注意】

程序显式地创建了一个string对象,用该函数调用的第三个实參。传递一个字符串字面值,将会导致编译时错误。由于此时,累加和的类型将是 constchar*,而 string的加法操作符所使用的操作数则各自是string和 constchar* 类型,加法的结果将产生一个string对象,而不是 constchar* 指针。

find_first_of的使用:

这个算法带有两对迭代器參数来标记两段元素范围,在第一段元素范围内查找与第二段范围中随意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。假设找不到匹配元素。则返回第一个范围的end迭代器。

//使用find_first_of统计有多少个数字在这两个容器中同一时候出现
size_t cnt = 0;
vector<int>::iterator iter = iVec1.begin(); //在while的第一次循环中,遍历整个iVec1范围。 //第二次以及兴许的循环迭代则仅仅考虑iVec1中尚未匹配的部分
while ((iter = find_first_of(iter,iVec1.end(),iVec2.begin(),iVec2.end())) != iVec1.end())
{
cout << *iter << endl;
++ cnt;
++ iter;
}
cout << "cnt = " << cnt << endl;

【关键概念:迭代器实參类型,P340,值得细致品读】

//P341 习题11.3
int main()
{
vector<int> iVec;
ifstream inFile("input");
int val; while (inFile >> val)
{
iVec.push_back(val);
} int sum = accumulate(iVec.begin(),iVec.end(),0);
cout << sum << endl;
}

C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】的更多相关文章

  1. C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法

    STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用 ...

  2. C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)

    STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...

  3. C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)

    STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的 ...

  4. C++ Primer 学习笔记_43_STL实践与分析(17)--再谈迭代器【中】

    STL实践与分析 --再谈迭代器[中] 二.iostream迭代[续] 3.ostream_iterator对象和ostream_iterator对象的使用 能够使用ostream_iterator对 ...

  5. C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法

    STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进 ...

  6. C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】

    STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector< ...

  7. C++ Primer 学习笔记_33_STL实践与分析(7) --容器适配器

    STL实践与分析 --容器适配器 引: 除了顺序容器.标准库还提供了三种顺序容器适配器:queue,priority_queue和stack.适配器是标准库中的概念.包含容器适配器,迭代器适配器和函数 ...

  8. C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】

    STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范 ...

  9. C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序

    STL实践与分析 --容器的综合应用:文本查询程序 引言: 本章中最重点的实例.由于不须要用到multiset与multimap的内容.于是将这一小节提到了前面.通过这个实例程序,大师分析问题的智慧, ...

随机推荐

  1. NDK-gdb的错误ERROR(不同于上一篇): Could not extract package's data directory...的解决方法

    这个问题比较龟毛. 我的系统在4.0.4上一直调试好好的,到了2.2的系统居然fail.能检查的地方全部检查过了,居然不行. 最后仔细差了一遍,居然是由于/data目录的属性是777导致.ndk-gd ...

  2. CentOS 6.4下编译安装MySQL 5.6.16

    一.卸载旧版本号MySql 1.rpm卸载: 1> 检查安装包: rpm -qa | grep mysql 2> 普通删除: rpm -e mysql-5.6.16.rpm 3> 强 ...

  3. CentOS6-釋放ip重新分配,centos7 ifconifg没有ip

    http://bbs.csdn.net/topics/390725823 系统win7 ,dhcp自动获取ip虚拟机是10.0 安装之后我装了ubuntu  选用 NAT网络, 刚装完我能上网 ,但是 ...

  4. 《转》python 网络编程

    原地址:http://blog.163.com/benben_long/blog/static/19945824320121225918434/ 网络客户端: 1. 理解socket: socket是 ...

  5. virtenv 0.8.6 发布,虚拟桌面配置工具 - 开源中国社区

    virtenv 0.8.6 发布,虚拟桌面配置工具 - 开源中国社区 virtenv 0.8.6 发布,virtenv 是一个用 QT4 开发的应用,用来配置和启动基于 LXC 的虚拟桌面环境.该容器 ...

  6. POJ 2826 An Easy Problem?! 好的标题

    受该两块木板以形成槽的效果.Q槽可容纳雨水多,注意雨爆跌,思想是非常easy,分类讨论是有点差. 1.假定两条线段不相交或平行,然后再装0: 2.有一个平行x轴.连衣裙0. 3.若上面覆盖以下的,装0 ...

  7. AccountManager使用教程

    API解读 这个类给用户提供了集中注冊账号的接口.用户仅仅要输入一次账户password后,就能够訪问internet资源. 不同的在线服务用不同的方式管理用户,所以account manager 为 ...

  8. 微信支付.net官方坑太多,我们来精简

    原文:微信支付.net官方坑太多,我们来精简 微信支付官方坑太多,我们来精简 我把官方的代码,打包成了 an.wxapi.dll. 里面主要替换了下注释.呵呵.然后修改了几个地方. 修改一.Confi ...

  9. .Net程序猿乐Android开发---(4)注册页面布局

    接下来我们介绍的登陆页面布局,在本节中,我们看一下注册页面布局,页面布局大同小异,来一起熟悉下基本控件的使用方法. 效果图: 1.加入注冊页面 右键选中layout目录,加入注冊页面.例如以下图 点击 ...

  10. Object.wait()的使用方法示例(转)

    本文节选自 Effective Java by Joshua Bloch 和 Concurrent Programming in Java by Doug Lea. 1.3 原子数据的同步 java语 ...