STL包含很多处理容器的非成员函数:

sort()

copy()

find()

random_shuffle()

set_union()

set_intersection()

set_difference()

transform()

它们的总体设计是相同的,都使用迭代器来标识要处理的数据区间和结果的放置位置。

有些函数还接受一个函数对象参数,并使用它来处理数据。

对于算法函数设计来说、有两个主要的通用部分:

1)都使用模板来提供泛型;

2)都使用迭代器来提供访问容器中数据的通用表示;

因为指针是一种特殊的迭代器,因此诸如copy()等STL函数可用于常规数组。

统一的容器设计使得不同类型的容器之间具有明显关系。

====================================================

一、算法组:

STL将算法库分成4组:

1)非修改式序列操作

2)修改式序列操作

3)排序和相关操作

4) 通用数字运算

非修改式序列操作对区间中的每个元素进行操作。这些操作不修改容器的内容。

修改式序列操作也对区间中的每个元素进行操作。它们可以修改容器的内容。可以修改值,也可以修改值的排列顺序。

排序和相关操作包括多个排序函数(包括sort())和其他各种函数,包括集合操作。

数字操作包括将区间的内容累积、计算两个容器的内部乘积、计算小计、计算相邻对象差的函数。

====================================================

二、算法的通用特征:

STL函数使用迭代器和迭代器区间。从函数原型可知有关迭代器的假设。

例如:copy()函数的原型如下

template<class InputIterator,  class OutputIterator>

OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);

对算法进行分类的方式之一,就是按结果放置的位置进行分类。

有些算法就地完成工作,有些则创建拷贝。

在sort()函数完成时,结果被存放在原始数据的位置上,因此sort()是就地算法

copy()函数将结果发送到另一个位置,所以它是复制算法

transform()函数可以以这两种方式完成工作。与copy()相似,它使用输出迭代器指示结果的存储位置;

与copy()不同的是,transform()允许输出迭代器指向输入区间,因此它可以用计算结果覆盖原来的值。

有些算法有两个版本:就地版本复制版本。STL的约定是,复制版本的名称将以_copy结尾

例如,函数replace()的原型如下:

template<class ForwardIterator, class T>

void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);

它将所有的old_value替换为new_value,这是就地发生的。

复制版本的原型如下:

template<class InputIterator, class OutputIterator, class T>

OutputIterator replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value);

结果被复制到result指定的新位置。

注意replace_copy返回类型为OutputIterator,对于复制算法而言,统一的约定是,返回一个迭代器,该迭代器指向复制的最后一个值后面的一个位置。

还有一种常见的变体:

以_if结尾的;根据将函数应用于容器元素得到的结果来执行操作。//这段话很绕,不是很理解

原型如下:

template<class ForwardIterator, class Predicate, class T>

void replace_if(ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value);

Predicate是模板参数名称,可以为T或者U。然而,STL选择用Predicate来提醒用户,实参应模拟Predicate概念。

同样,STL使用诸如Generator和BinaryPredicate等术语来指示必须模拟其他函数对象概念的参数。

虽然STL文档可以指定迭代器或函数符的需求,但编译器不会对此进行检查。

如果您使用了错误的迭代器,则编译器试图实例化模板时,将出现大量错误信息。

====================================================

三、STL和string类:

sting类虽然不是STL的组成部分,但设计它时考虑到了STL。

例如,它包含begin()、end()、rbegin()和rend()等成员,因此可以使用STL接口。

下面的例子是用STL显示了一个词的字母可以得到的所有排列组合。

 // strgst1.cpp -- applying the STL to a string
#include <iostream>
#include <string>
#include <algorithm> int main()
{
using namespace std;
string letters;
cout<<"Enter the letter grouping (quit to quit): ";
while(cin>>letters && letters != "quit")
{
cout<<"Permutations of "<<letters<<endl;
sort(letters.begin(), letters.end());
cout<<letters<<endl;
while (next_permutation(letter.begin(), letter.end()))
cout<<letter<<endl;
cout<<"Enter next sequence (quit to quit): ";
}
cout<<"Done.\n";
return ;
}

====================================================

四、函数和容器方法:

有时可以选择使用STL方法或者STL函数。通常方法是更好的选择

因为,它更适合特定的容器,其次容器方法作为成员函数,它可以使用模板类的内存管理工具,从而在需要的时候调整容器的长度。

举个例子,假设有一个由数字组成的链表,并要删除链表中某个特定值(例如4)的所有实例。

如果la是一个list<int>对象,则可以使用链表的remove()方法:

la.remove(4);  //remove all 4s from the list;

调用该方法后,链表中所有值为4的元素都将被删除,同时链表的长度将被自动调整。

还有一个名为remove()的STL算法,它不是由对象调用,而是接受区间参数。因此如果lb是一个list<int>对象,则调用该函数的代码如下:

remove(lb.begin(), lb.end(), 4);

然而,由于该remove()函数不是成员,因此不能调整链表的长度。它将没被删除的元素放在链表的开始位置,并返回一个指向新的超尾值得迭代器。

这样,便可以用迭代器来修改容器的长度。

例如,可以使用链表的erase()方法来删除一个区间,该区间描述了链表中不再需要的部分。

下面是一个例子,演示了如何进行:

 //listrmv.cpp  -- applying the STL to a string
#inclue <iostream>
#inclue <list>
#inclue <algorithm> void Show(int);
const int LIM = ; int main()
{
using namespace std;
int ar[LIM] = {,,,,,,,,,};
list<int> la(ar, ar+LIM);
list<int> lb(la);
cout<<"Original list contents:\n\t";
for_each(la.begin(), la.end(), Show); cout<<endl;
la.remove();
cout<<"After using the remove() method:\n";
cout<<"la:\t";
for_each(la.begin(), la.end(), Show);
cout<<endl; list<int>::iterator last;
last = remove(la.begin(), lb.end(), );
cout<<"After using the remove() function:\n";
cout<<"lb:\t";
for_each(lb.begin(), lb.end(), Show);
cout<<endl; lb.erase(last, lb.end());
cout<<"After using the erase() method:\n";
cout<<"lb:\t";
for_each(lb.begin(), lb.end(), Show);
cout<<endl;
return ;
} void Show(int v)
{
std::cout<<v<<' ';
}

程序输出:

Original list contents:
4 5 4 2 2 3 4 8 1 4
After using the remove() method:
la: 5 2 2 3 8 1
After using the remove() function:
lb: 5 2 2 3 8 1 4 8 1 4
After using the erase() method:
lb: 5 2 2 3 8 1

====================================================

五、使用STL:

STL是一个库,其组成部分被设计成协同工作。

STL组件是工具,但也是创建其他工具的部件。

接下来用一个例子来练习:

假设要编写一个程序,让用户输入单词。希望最后得到一个按输入顺序排列的单词列表、

一个按字母顺序排列的单词列表(忽略大小写),并记录每个单词被输入的次数。

出于简化的目的,假设输入的过程中不添加数字和标点符号。

输入和保存单词列表很简单,创建一个vector<string>对象,并用push_back()将输入的单词添加到矢量中

vector<string> words;

string input;

while(cin>>input && input != 'quit')

  words.push_back(input);

接下来如何将得到的单词列表按字母顺序排列

为了避免覆盖原始数据,不能够使用就地算法。

可以创建一个set<string>对象,然后将矢量中的单词复制到集合中(需要使用迭代器)。

set<string> wordset;

transform(words.begin(), words.end(), insert_iterator<set<string>>(wordset, wordset.begin()), ToLower)

至于ToLower函数的编写如下:

string & ToLower(string & st)

{

  transform(st.begin(), st.end(), st.begin(), tolower);

  return st ;

}

有些情况下,tolower()函数被定义为int tolower(int),而我们希望函数与元素类型相匹配。

char toLower(char ch) {return tolower(ch);}

要获得每个单词在输入中出现的次数,可以使用count()函数。

它将一个区间和一个值作为参数,并返回这个值在区间中出现的次数。

map<string, int> wordmap;

set<string>::iterator si;

for(si = wordset.begin(), si != wordset.end(), si++)

  wordmap.insert(pair<string, int>(*si, count(words.begin(), words.end(), *si)));

map类有个有趣的特征,可以用数组表示法(将键作为索引)来访问存储的值。

例如,wordmap["the"]表示与键“the”相关联的值,这里是字符串“the”出现的次数。

因为wordset容器保存了wordmap使用的全部键,所以可以用下面的代码来存储结果:

for(si = wordset.begin(), si != wordset.end(), si++)

  wordmap[*si] = count(words.begin(), words.end(), *si);

同样也可以使用数组表示法来报告结果:

for(si = wordset.begin(), si !=wordset.end(), si++)

  cout<<*si<<": "<<wordmap[*si]<<endl;

 //usealgo.cpp -- using several STL elements
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iteraotor>
#include <algorithm>
#include <cctype> using namespace std; char toLower(cahr ch) {return tolower(ch);}
string & ToLower(string & st);
void display(const string & s); int main()
{
vector<string> words;
cout<<"Enter words(enter quit to quit):\n";
string input;
while(cin>>input && input != "quit")
words.push_back(input); cout<<"You entered the following words:\n";
for_each(words.begin(), words.end(), display);
cout<<endl; //place words in set, converting to lowecase
set<string> wordset;
transform(words.begin(),words.end(), insert_iterator<set<string>>(wordset, wordset.begin()));
cout<<"\nAlphabetic list of words:\n";
for_each(wordset.begin(), wordset.end(), display);
cout<<endl; //place word and frequency in map
map<string, int> wordmap;
set<string> :: iterator si;
for(si = wordset.begin(); si != wordset.end(); si++)
wordmap[*si] = count(words.begin(), words.end(), *si);
//display map contents
cout<<"\nWord frequency:\n";
for(si = wordset.begin(); si != wordset.end(); si++)
cout<<*si<<": "<<wordmap[*si]<<endl;
return ;
} string & ToLower(string & st)
{
transform(st.begin(), st.end(), st.begin(), toLower);
return st;
} woid display(const string & s)
{
cout<<s<<" ";
}

STL使用时应尽可能减少要编写的代码。

STL通用、灵活的设计将节省大量的工作。

另外,STL的设计者都是非常关心效率的算法人员,

算法是经过仔细选择的,并且是内联的。

C++_标准模板库STL概念介绍4-算法的更多相关文章

  1. C++_标准模板库STL概念介绍1-建立感性认知

    标准模板库的英文缩写是STL,即Standard Template Library. STL里面有什么呢? 它提供了一组表示容器.迭代器.函数对象和算法的模板. 容器是一个与数组类似的单元,可以存储若 ...

  2. C++_标准模板库STL概念介绍5-其他库与总结

    C++还提供了其他一些类库,这些类库更加专用. 例如,头文件complex为复数提供了类模板complex,包含用于float.long和long double的具体化. 这个类提供了标准的复数运算以 ...

  3. C++_标准模板库STL概念介绍2-泛型编程

    有了之前使用STL的经验后,接下来讨论泛型编程及其底层的理念: 首先我们知道STL只是泛型编程的一种: 而面向对象的编程方式关注的是编程的数据方面: 而泛型编程关注的是算法: 但是,他们之间的一个重要 ...

  4. C++_标准模板库STL概念介绍3-函数对象

    函数对象也叫做函数符(functor). 函数符是可以以函数方式和( )结合使用的任意对象. 包括函数名,指向函数的指针,重载了()运算符的类对象. 可以这样定义一个类: class Linear { ...

  5. STL学习系列之一——标准模板库STL介绍

    库是一系列程序组件的集合,他们可以在不同的程序中重复使用.C++语言按照传统的习惯,提供了由各种各样的函数组成的库,用于完成诸如输入/输出.数学计算等功能. 1. STL介绍 标准模板库STL是当今每 ...

  6. C++ 标准模板库STL 队列 queue 使用方法与应用介绍

    C++ 标准模板库STL 队列 queue 使用方法与应用介绍 queue queue模板类的定义在<queue>头文件中. 与stack模板类很相似,queue模板类也需要两个模板参数, ...

  7. 标准模板库--STL

    标准模板库STL 1.泛型程序设计 C++ 语言的核心优势之一就是便于软件的重用 C++中有两个方面体现重用: 1.面向对象的思想:继承和多态,标准类库 2.泛型程序设计(generic progra ...

  8. 实验8 标准模板库STL

    一.实验目的与要求: 了解标准模板库STL中的容器.迭代器.函数对象和算法等基本概念. 掌握STL,并能应用STL解决实际问题. 二.实验过程: 完成实验8标准模板库STL中练习题,见:http:// ...

  9. cb22a_c++_标准模板库_STL_map_multimap红黑树(数据结构)关联容器

    cb22a_c++_标准模板库_STL_map_multimap红黑树(数据结构)关联容器map(映射,key不能重复,一对一对的,value_type(1, "one")),mu ...

随机推荐

  1. NFA/DFA算法

    1.问题概述 随着计算机语言的结构越来越复杂,为了开发优秀的编译器,人们已经渐渐感到将词 法分析独立出来做研究的重要性.不过词法分析器的作用却不限于此.回想一下我们的老师刚刚开始向我们讲述程序设计的时 ...

  2. 算法描述》关于LIS的nlogn方法

    上次TYVJ有一道裸LIS,然而我当时直接打了一个N^2暴力就草草了事,然后就ZZ了,只拿了60分,其实NlogN的LIS和N^2的差的不多,只是没有N^2,好想罢了,鉴于某学弟的要求,所以就重现一下 ...

  3. PHP数组在循环的时候修改本身的值

    这样的修改并不是修改本身,$item就相当于赋值了一份数组中的值,就跟JAVA中的值方式传递值类型一样,我只是拿了你的值,并不是拿了你的内存地址,所已$item的改变,并不会影响数组 第一种方式就是直 ...

  4. 一,安装python

    在Windows上安装Python 首先,从Python的官方网站www.python.org下载最新的2.7.9版本,地址是这个: http://www.python.org/ftp/python/ ...

  5. c++ (proxy)代理模式

    假设我们有几个具有相似的窗体,都包含关闭窗体(closeButton)和按钮单击事件(ClickButton)我们在处理时,不想直接操作每个窗体,可以请求代理. #include<iostrea ...

  6. PrimeNG01 angular集成PrimeNG

    1 开发环境 本博文基于angular5 2 步骤 2.1 创建angular5项目 详情参见百度 2.2 下载PrimeNG依赖 npm install primeng --save npm ins ...

  7. 10个强大的Javascript表单验证插件推荐

    创建一个JavaScript表单验证插件,可以说是一个繁琐的过程,涉及到初期设计.开发与测试等等环节.实际上一个优秀的程序员不仅是技术高手,也应该是善假于外物的.本文介绍了10个不错的JavaScri ...

  8. linux下scsi共享磁盘的简单搭建

    linux下scsi共享磁盘的简单搭建 Scsi 共享磁盘需要我先有空余的分区,或者可以在虚拟机里面添加一块磁盘,安装所需的软件我在虚拟机里面添加了一块硬盘,分了一个主分区,sdb1 1G,将这个用s ...

  9. requests基础

    爬虫的基本原理:爬虫本质上是模拟人浏览信息的过程,只不过他通过计算机来达到快速抓取筛选信息的目的.所以我们想要写一个爬虫,最基本的就是要将我们需要抓取信息的网页原原本本的抓取下来.这个时候就要用到re ...

  10. 处理iOS设备的屏幕旋转

    某些情况下,不强制的给用户唯一的屏幕角度给用户.这样用户可以旋转手机得到不同的视觉体验. 最简单的就是safari,横看竖看都可以. 这时需要捕捉用户的屏幕旋转事件并处理.很简单,才两步.比把大象装冰 ...