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. pygame系列

    在接下来的blog中,会有一系列的文章来介绍关于pygame的内容,pygame系列偷自http://www.cnblogs.com/hongten/p/hongten_pygame_install. ...

  2. 世纪互联、微软Azure与无穷小微积分

              今年9月25日,世纪互联正式开通微软Azure商用服务,有感.          我是世纪互联创业历程的见证人(之中的一个),现在看到世纪互联推出微软Azure公有云的商用服务,心 ...

  3. 《Javascript高级程序设计》读书笔记之对象创建

    <javascript高级程序设计>读过有两遍了,有些重要内容总是会忘记,写一下读书笔记备忘 创建对象 工厂模式 工厂模式优点:有了封装的概念,解决了创建多个相似对象的问题 缺点:没有解决 ...

  4. [Unity3D]Unity4全新的动画系统Mecanim

    Unity4.X添加一个新的动画系统,以取代原有的3.X旧的动画系统,全新的动画系统Mecanim是官方推荐,它使我们能够写更少的代码实现连续动画. 效果图 Unity3.X中动画系统播放动画 使用播 ...

  5. 第五章_JSTL

    5.1.下载JSTL http://jstl.java.net 5.2.JSTL类库 类别 下属功能 URI 前缀 Core 变量支持 http://java.sun.com/jsp/jstl/cor ...

  6. 《Effective C++ 》学习笔记——规定10

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  7. POJ2676 Sudoku [数独]

    好题,也非常有用,犯了几个错误 1.在枚举赋值的时候,思维有个错误:当当前的赋值不能填完这个数独,应该是继续下一个循环,而不是return false 终止枚举 2.Generic Programin ...

  8. BZOJ 1449 JSOI2009 球队收益 费用流

    题目大意:给定nn支球队.第ii支球队已经赢了winiwin_i场.输了loseilose_i场,接下来还有mm场比赛.每一个球队终于的收益为Ci∗x2i+Di∗y2iC_i*x_i^2+D_i*y_ ...

  9. awk与sed:关于多行的样本

    几天前CSDN看到一个帖子http://bbs.csdn.net/topics/390848841,楼主贴了以下的问题: 例: 12345 67890 1234567890 123 4567890 怎 ...

  10. 查看linux系统版本号命令

    一.查看内核版本号命令: 1) [root@SOR_SYS ~]# cat /proc/version Linux version 2.6.18-238.el5 (mockbuild@x86-012. ...