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. ME21N增强提示警告消息

    在ME21N增强中,可以使用message的方法提示错误的消息,但警告消息使用message则提示不了,需要使用系统宏mmpur_message 提示. data:begin of lw_equp, ...

  2. VC6迁移到VS2008几个问题——良好的代码,从我做起,从现在开始。

    最近.有一个项目开发,需要使用一次项目的代码.只有当项目VC6下编译通过的,在VS2008下不一定编译通过,能编译通过也不一定能链接成功.以下总结一下我在一个VC6项目移植到VS2008中遇到的一些问 ...

  3. hdu 5090 Game with Pearls

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5090 题意:n个数,k,给n个数加上k的正倍数或者不加,问最后能不能凑成1 到 n的序列 题目分类:暴 ...

  4. win32收不到F10按键消息解决办法

    在WM_KEYDOWN中处理F10(VK_F10)消息总是获取不到,后来用spy++监听窗口消息发现按下F10并没有WM_KEYDOWN消息产生,而是产生了WM_SYSKEYDOWN http://b ...

  5. Delphi 中 FindWindow 和 FindWindowEx 找到外部进程,然后发送消息(比如最大化)

    FindWindow(lpClassName,        {窗口的类名}lpWindowName: PChar {窗口的标题}): HWND;              {返回窗口的句柄; 失败返 ...

  6. MSA2312 enclosure 闪断后

    故障描述:由于电源原因,导致整个扩展柜闪断,硬盘全部为leftover状态. 存储划分配置:之前满配的一套MSA2312,划分为4个vd,后面两个vd无影响,前面2个VD都是一半在1号柜子,一半在2号 ...

  7. chmod u+s(转)

    参看了 http://hi.baidu.com/hehongrong/item/b64a6d6b094cf634ac3e8382 里面说 -s :在文件执行时把进程的属主或组ID置为该文件的文件属主. ...

  8. OCP读书笔记(2) - 配置恢复

    RMAN的命令类型 1. sqlplus命令 [oracle@oracle admin]$ export ORACLE_SID=orcl [oracle@oracle admin]$ rman tar ...

  9. [PHP]利用MetaWeblog API实现XMLRPC功能

    [PHP]利用MetaWeblog API实现XMLRPC功能 | OWNSELF [PHP]利用MetaWeblog API实现XMLRPC功能 Windows Live Writer是一款小巧的写 ...

  10. Activity与Service通信的方式有三种:

    在博客园看到的,看着挺不错的,借来分享下 继承Binder类 这个方式仅仅有当你的Acitivity和Service处于同一个Application和进程时,才干够用,比方你后台有一个播放背景音乐的S ...