STL实践与分析

--初窥算法【下】

一、写容器元素的算法

一些算法写入元素值。在使用这些算法写元素时一定要当心。必须确保算法所写的序列至少足以存储要写入的元素。

1、写入输入序列的元素

写入到输入序列的算法本质上是安全的——仅仅会写入与指定输入范围数量同样的元素。

写入到输入序列的一个简单算法是fill函数:

    fill(iVec.begin(),iVec.end(),10);
fill(iVec.begin(),iVec.begin()+iVec.size()/2,0);

fill带有一对迭代器形參。用于指定要写入的范围,而所写的值是它的第三个形參的副本。假设输入范围有效,则可安全写入。

这个算法仅仅会对输入范围内已存在的元素进行写入操作

2、不检查写入操作的算法

fill_n函数带有的參数包括:一个迭代器、一个计数器以及一个值。fill_n函数假定对指定数量的元素做写操作是安全的。

    vector<int> iVec;
/**Error
*可是编译器不会报错,
*非常可能导致严重的执行时错误
*/
fill_n(iVec.begin(),10,0);

对于指定数目的元素做写入运算,或者写到目标迭代器的算法,都不检查目标的大小是否足以存储要写入的元素。

3、引入back_inserter

确保算法有足够的元素存储输出数据的一种方法是使用插入迭代器。在使用插入迭代器赋值时,会在容器中加入一个新元素,其值等于赋值运算的右操作数的值。

使用back_inserter的程序必须包括iterator头文件。

back_inserter函数是迭代器适配器。

迭代器适配器使用一个对象作为实參,并生成一个适应事实上參行为的新对象。在本例中,传递给back_inserter的实參是一个容器的引用

back_inserter生成一个绑定在该容器上的插入迭代器

在试图通过这个迭代器给元素赋值时,赋

值运算将调用push_back在容器中加入一个具有指定值的元素。

使用 back_inserter能够生成一个指向fill_n写入目标的迭代器:

    vector<int> iVec;
fill_n(back_inserter(iVec),10,0);

效果相当于在vec上调用push_back,在vec末尾加入10个元素,每一个元素的值都是0。

4、写入到目标迭代器的算法

第三类算法向目标迭代器写入未知个数的元素。

如:copy函数。copy带有三个迭代器參数:头两个指定输入范围,第三个则指向目标序列的一个元素。传递给copy的目标序列必须至少要与输入范围一样大。假设ilst是一个存放int型数据的 list对象,可例如以下将它copy给一 个vector对象:

    vector<int> iVec;
copy(iList.begin(),iList.end(),back_inserter(iVec));

copy从输入范围中读取元素,然后将它们复制给目标ivec。

当然,这个样例的效率比較差。最好应该对新构造容器的初始化式:

    vector<int> iVec(iList.begin(),iList.end());

5、算法的_copy版本号

有些算法提供所谓的“复制(copying)”版本号。

这些算法对输入序列的元素做出处理,但不改动原来的元素,而是创建一个新序列存储元素的处理结果。

replace算法就是一个非常好的样例。该算法对输入序列做读写操作,将序列中特定的值替换为新的值。

该算法带有四个形參:一对指定输入范围的迭代器和两个值。

每一个等于第一值的元素替换成第二个值。

    replace(iList.begin(),iList.end(),0,42);

假设不想改变原来的序列,则调用replace_copy函数。这个算法接受第三个迭代器实參,指定要保存调整后序列的位置:

vector<int> iVec;    replace_copy(iList.begin(),iList.end(),back_inserter(iVec),0,42);

//P343 习题11.6
int main()
{
int ia[] = {1,3,5,7,9,2,4,6,8,10};
fill_n(ia,sizeof(ia)/sizeof(*ia),0); for (size_t index = 0;index != sizeof(ia)/sizeof(*ia); ++index)
{
cout << *(ia + index) << endl;
}
}

//或者
int main()
{
vector<int> iVec;
iVec.resize(10);
fill_n(iVec.begin(),iVec.size(),0); for (vector<int>::iterator iter = iVec.begin(); iter != iVec.end(); ++iter)
{
cout << *iter << endl;
}
}

二、对容器元素又一次排序的算法

问题:

我们要分析一组儿童故事中所使用的单词。比如:它们使用了多少个由六个或以上字母组成的单词。每一个单词仅仅统计一次。

要求以长度的大小输出这些单词,对于同样长的单词,则以字典顺序输出。

分析:

为 了解此问题,要做以下几项操作:

1.去掉全部反复的单词。

2.按单词的长度排序。

3.统计长度等于或超过6个字符的单词个数。

上述每一步都可使用泛型算法实现。

样例:

为了说清楚,使用以下这个简单的故事作为我们的输入:

	the quick red fox jumps over the slow red turtle

对于这个输入,我们的程序应该产生例如以下输出:

	1 word 6 characters or longer

1)、去除反复

假设我们的输入存储在一个名为words的 vector对象中,第一个子问题是将words中反复出现的单词去除掉:

    sort(words.begin(),words.end());
vector<string>::iterator iter = unique(words.begin(),words.end()); words.erase(iter,words.end());

vector对象包括使用的全部单词。

首先对此vector对象排序。

sort算法带有两个迭代器实參,指出要排序的元素范围。这个算法使用默认的小于(<)操作符比較元素。在本次调用中,要求对整个vector对象排序。

此时,vector对象内:

fox

jumps

over

quick

red

red

slow

the

the

turtle

注意:red和the反复了。

2)、unique的使用

unique算法带有两个指定元素范围的迭代器參数。

该算法删除相邻的反复元素,然后又一次排列输入范围内的元素,而且返回一个迭代器,表示无反复的值范围的结束。

	unique(words.begin(),words.end());

语句调用结束后:

fox

jumps

over

quick

red

slow

the

turtle

the

red

【注意:】

words的大小并没有改变,依旧保存着10个元素;仅仅是这些元素的顺序改变了。unique实际上并没有删除不论什么元素,而是将无反复的元素拷贝到序列的前端,从而覆盖相邻的反复元素

3)、使用容器操作删除元素

调用erase实现删除反复的项。

这个函数调用从end_unique指向的元素開始删除,直到words的最后一个元素也删除掉为止。

调用之后,words存储输入的 8个不同样的元素。

算法不直接改动容器的大小。假设须要加入或删除元素,则必须使用容器操作。【好像有点不负责任的意思O(∩_∩)O~】

4)、定义须要的有用函数

两个接下来要使用的函数stable_sort和count_if。这两个是使用stable_sort和count_if算法的配套函数,称为谓词。谓词是做某些检測的函数,返回用于条件推断的类型,指出条件是否成立。

bool isShorter(const string &s1,const string &s2)
{
return s1.size() < s2.size();
}
bool GT6(const string &s)
{
return s.size() >= 6;
}

5)、排序算法

除了sort之外,标准库还定义了stable_sort算法,stable_sort保留相等元素的原始相对位置。

sort和 stable_sort都是重载函数。当中一个版本号使用元素类型提供的小于(<)操作符实现比較。第二个重载版本号带有第三个形參:比較元素所使用的谓词函数的名字。

这个谓词函数必须接受两个实參,实參的类型必须与元素类型同样,并返回一个可用作条件检測的值。

如:

stable_sort(words.begin(),words.end(),isShorter);

调用后:

fox

red

the

over

slow

jumps

quick

turtle

6、统计长度不小于6的单词数

使用count_if算法实现:

    vector<string>::size_type cnt = count_if(words.begin(),words.end(),GT6);

执行count_if函数时。首先读取他的头两个參数所标记的范围内的元素。每读取一个元素,则将其传递给第三个实參表示的谓词函数。

7、将全部程序放在一起

bool isShorter(const string &s1,const string &s2)
{
return s1.size() < s2.size();
}
bool GT6(const string &s)
{
return s.size() >= 6;
} int main()
{
vector<string> words;
ifstream inFile("input"); string word;
while (inFile >> word)
{
words.push_back(word);
} sort(words.begin(),words.end());
vector<string>::iterator end_unique = unique(words.begin(),words.end()); words.erase(end_unique,words.end()); stable_sort(words.begin(),words.end(),isShorter); vector<string>::size_type wc = count_if(words.begin(),words.end(),GT6);
cout << wc << " words 6 characters or longer." << endl; cout << "Words:" << endl;
for (vector<string>::iterator it = words.begin(); it != words.end(); ++it)
{
cout << *it << endl;
}
}

//P347 习题11.9
bool GT4(const string &str)
{
return str.size() >= 4;
} int main()
{
ifstream inFile("input");
vector<string> strVec;
string str; while (inFile >> str)
{
strVec.push_back(str);
} sort(strVec.begin(),strVec.end());
vector<string>::iterator end_unique =
unique(strVec.begin(),strVec.end()); vector<string>::size_type word_cnt = count_if(strVec.begin(),end_unique,GT4); cout << "Now! Have " << word_cnt << " words made of 4 characters or longer." << endl;
for (vector<string>::iterator iter = strVec.begin(); iter != end_unique; ++iter)
{
cout << *iter << endl;
}
}

//习题11.10
bool GT6(const string &str)
{
return str.size() >= 6;
} int main()
{
ifstream inFile("input");
vector<string> strVec;
string str; while (inFile >> str)
{
strVec.push_back(str);
} vector<string>::size_type word_cnt = 0;
vector<string>::iterator first = strVec.begin(); while ((first = find_if(first,strVec.end(),GT6)) != strVec.end())
{
++ word_cnt;
++ first;
} cout << word_cnt << endl;
cout << "WORD:" << endl;
for (vector<string>::iterator iter = strVec.begin(); iter != strVec.end(); ++iter)
{
cout << *iter << endl;
}
}

版权声明:本文博主原创文章。博客,未经同意不得转载。

C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】的更多相关文章

  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 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】

    STL实践与分析 --概述.初窥算法[上]     标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的. ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 基于.net开发chrome核心浏览器【二】

    原文:基于.net开发chrome核心浏览器[二] 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一] 二: 相关资源介绍: chrome Frame: 让IE有一颗chrome的心, ...

  2. Radmin远程控制软件

    Radmin远程控制软件 日期:2015-08-20     作者:lujl   Radmin是一款快速的远程控制软件,可以用来远程管理公司或个人计算机来实现远程办公.你可以通过鼠标和键盘来控制远程的 ...

  3. IOS开发-通知与消息机制

    在多数移动应用中不论什么时候都仅仅能有一个应用程序处于活跃状态.假设其它应用此刻发生了一些用户感兴趣的那么通过通知机制就能够告诉用户此时发生的事情. iOS中通知机制又叫消息机制,其包含两类:一类是本 ...

  4. C语言获取文件SHA1哈希

    安全散列算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)它定义了数字签名算法(Digital Signatur ...

  5. Just like normal variables,

    Just like normal variables, pointers can be declared constant. There are two different ways that poi ...

  6. 【Hibernate步步为营】--双向关联一对一映射具体解释(一)

    一对一的映射在对象模型中是常常见到的,为了将对象模型转换为关系模型就必须在映射文件里进行配置,上篇文章讨论了一对一映射的单向关联的情况,重点是<one-to-one>标签的使用,须要在映射 ...

  7. 【剑指offer】q50:树节点最近的祖先

    #@ root: the root of searched tree #@ nodeToFind: the tree-node to be found #@ path: the path from r ...

  8. dbus 和 policykit 实例篇(python) ()转

    使用policykit 的程序一般都有一个dbus daemon程序来完成相关操作,这个dbus daemon 会在系统注册一个system bus 服务名,用于响应要求root privileged ...

  9. 【原创】leetCodeOj ---Construct Binary Tree from Preorder and Inorder Traversal 解题报告

    原题地址: https://oj.leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 题目 ...

  10. html5移动开发--js温馨提示

    1.a标签执行js笔试 <a id="myID" href="javascript:myfuction();"></a> 2.实时监听i ...