使用Map
Map的作用,体现在你想查询某个字眼(单词,或者从句子里切分出来的某一子字符串这样的东西等)的出现次数的时候(并加以分析时)可以使用。
要包含头文件#include<map>
,格式一般为map<key,value>前者是字眼,后者为该字眼出现次数。
用法举例:
#include<map>
#include<string>
map<string,int>words;
string tword;
while(cin>>tword)
{
words[tword]++;
}//字数统计,words[tword]取出与tword相应的value
如果tword不在map里,则tword会被自动放入map中,并获得默认值0
map<string,int>::iterator it=words.begin();
it->first;//first对应key,(此时first就像结构体里的成员一样,只不过充当结构体角色的就是map),此代码配合cout可输出字眼是什么
it->second;//second对应value,此代码配合cout可输出字眼在map里出现的次数
map自带find()函数(map查询法)
words.find("vermeer");
map<string,int>::iterator it;
it=words.find("vermeer");
count=it->second;//字眼在map里出现的次数赋值给count
如果key(“vermeer”)已放在words这个map中,map自带的find()会返回一个iterator,指向key/value形成pair(pair class为标准库的一员),如果没有放在其中,则会返回map.end()(这里为words.end())
map自带count()函数(map查询法)
string search_word("vermeer");//可以定义string类型常量
words.count(search_word);
count()会返回某指定的字眼(单词,或者从句子里切分出来的某一子字符串这样的东西等)在map内的个数
map只能存储一份key值,如果先要存储多份,请用multimap。
使用Set
作用:想知道某值是否存在于某个集合内,比如用于图结点的遍历,用set存储每个遍历过的结点,等到遍历移动到下一个结点前,先查询set以判断下一个结点是否已被遍历过,或者你可以用set来存储需要排除的字眼,在统计很多字眼的时候可以跳过那些排除的字眼
用之前包含头文件#include<set>
用法举例:
#include<set>
#include<map>
#include<string>
map<string,int>words;
stirng tword;
set<string>word_exclusion;//set只有key值!!!
//map和set搭配使用的情况
while(cin>>tword)
{
if(word_exclusion.count(tword));
//如果tword是在需要排除的字眼的集合内,则这个tword所属的迭代被跳过
//即相当于if(1),如果不在需要排除的字眼的集合内,则相当于if(0),不走if里头
{
continue;
}
words[tword]++;//到达此地,说明tword并不属于需要排除的字眼的集合内,那就将其纳入map内,表示该字眼出现了一次!
}
set只能存储一份key值,如果先要存储多份,请用multikey。
默认情况下,set里的元素默认升序排列(从小到大排列)
举个例子:
int ia[10]={1,3,5,8,5,3,1,5,8,1};
vector<int>vec(ia,ia+10);
set<int>iset(vec.begin(),vec.end());
此时iset这个set里的元素排列顺序为1,3,5,8,这里iset这个set复制了只保留一个vec中每个不同的元素,排除了其他和1,3,5,8相同的元素(体现了set的特点,若某值存在某集合内,第一次出现吸收进set,第二次及以后出现就不吸收进来。)
- 给set加入单一元素,用单参数的insert():
iset.insert(ival);//ival为单一元素
- 给set加入多个元素,用双参数的insert():
iset.insert(vec.begin(),vec.end());/
- 在set上面迭代,需要个迭代器(泛型指针),如
set<int>::iterator it=iset.begin();
for(;it!=iset.end();++it)
{
cout<<*it<<' ';
}
cout<<end;
还有其他和set相关的泛型算法
set_intersection(),set_union(),set_difference(),set_symmetric_difference(),具体用法可以搜索引擎查询。
如何使用Iterator Inserter
主要是之前的filter()的复制操作是用赋值运算符来完成的,iterator inserter运用了插入来让复制操作或者是copy()及其相似的泛型算法更加灵活,也就是你不用再规定固定大小的目标(接收复制元素的)容器了。
标准库给了三个insertion adapter。如下
- back_inserter(),以容器的push_back()来执行插入(复制)操作,适合vector,传入b_i的参数为(目标)容器本身。
vector<int>result_vec;
unique_copy(ivec.begin(),ivec.end(),back_inserter(result_vec);
这样,就把ivec这个容器的元素从首到尾依次插进result_vec这个容器里。
- inserter(),以容器的insert()函数执行插入(复制)操作,inserter函数接收两个参数,一个(目标)容器,一个指向(目标)容器内的插入操作的起点的泛型指针,我举个例子你就能很好的明白
vector<string>svec_res;
unique_copy(svec.begin(),svec.end(),inserter(svec_res,svec_res.end());
这里inserter函数接受了string型vector容器及其指向这个容器的末尾元素位置的下一个位置的泛型指针。
- front_inserter(),以容器的push_front()函数执行插入(复制)操作。适用于list和deque
list<int>ilist_clone;
copy(ilist.begin(),ilist.end(),front_inserter(ilist_clone));
//front_inserter()只接受一个参数,即目标容器
想使用上面三种insertion adapter,必须包含头文件#include<iterator>
注意:insertion adapter不可用于array上!
使用了insertion adapter后,程序看起来可读性高,效率更快(在容器(比如vector)末端插入元素的情况下,这时候必选back_inserter()。这样比赋值表达式少计算右式和整体的值从而提高效率。我的理解是这样,怎么好理解怎么来)
使用iostream Iterator
如果你想从标准输入设备读取数据,并可能存在某个地方(比如容器里),然后操作一番数据(或容器),然后再输出(写回)到标准输出设备中,那么你需要iostream Iterator
一般的解法是基于cin>>对象,操作,cout<<该对象或其他对象
标准库有定义的iostream iterator类,供输入输出使用。
输入是istream_iterator,输出是ostream_iterator。支持单一类型读取和写入,使用这两个iterator前,必须包含头文件#include<iterator>
- 如何使用istream_iterator
istream_iterator<string>is(cin);
将is定义为一个”绑定至标准输入设备“的istream_iterator.它可以作为泛型指针first
istream_iterator<string>eof;
eof即end-of-file,可作为泛型指针last,表示要读取的最后一个元素的下个位置!!!!注意,这个istream_iterator在定义时没有指定istream对象。
用法举例:
copy(is,eof,back_inserter(text));
is相当于泛型指针first,eof相当于泛型指针last,back_inseter是insertion adapter,text是string型容器
- 如何使用ostream_iterartor
这是标示某元素(比如字符串元素)的输出位置。
ostream_iterator<string>os(cout," ");
这是将os定义为一个”绑定至标准输出设备“的ostream_iterator,**此标准输出设备供我们输出类型为string元素。**第二个参数是字符串常量或者C风格字符串都行。这里是用来表示各个元素被输出的时候中间空一格。默认情况下,输出的各个元素并无任何分隔符。
copy(text.begin(),text.end(),os);
这是一种使用方式,copy(),copy将存储在text中的每个元素一一写入os所标示的ostream上,每个元素之间一个空格。
使用实践:
//屏幕输入屏幕输出实例(ctrl+z结束输入)
#include<iostream>
#include<iterator>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{//目的:目的:先读入屏幕里的数据给一个容器(这里为string型),然后给容器里的元素排序,然后写入到屏幕。
istream_iterator<string>is(cin);//定义is这个istream_iterator指向标准输入设备。
//注意类型要和你想接收读取的元素的容器类型要一致
istream_iterator<string>eof;//定义eof这个istream_iterator指向读取的最后一个元素的下一个位置!!记住
//输入的时候怎样结束输入呢?win下 ctrl+z;linux下 ctrl+d 。!!!
vector<string>text;//接收读取的元素的string型容器(vector)
copy(is,eof,back_inserter(text));//采用insertion adapter里的back_inserter()函数更有效率
sort(text.begin(),text.end());//给接收读取的元素的string型容器text排个序
ostream_iterator<string>os(cout," ");//定义os这个ostream_iterator指向标准输出设备,并输出每个元素时输出一个空格
copy(text.begin(),text.end(),os);//依次输出text里所有元素
return 0;
}
让我们看看程序运行结果:
因为容器进行了排序,容器内组成的元素不同可能输出(写入)的次序就不同,所以输出(写入)的顺序是排完序后容器的元素
(容器第一个元素w小于第二个元素n,故n开头的string型元素排在前)
再看个程序运行例子你就能明白(我所说的上面的内容):
//文件输入输出实例
#include<iostream>
#include<string>
#include<vector>
#include<iterator>
#include<fstream>
#include<algorithm>
using namespace std;
int main()
{//目的:先读入文件里的数据给一个容器(这里为string型),然后给容器里的元素排序,然后写入到另一个文件中。
ifstream in_file("input_file.txt");//注意,你得先自己创建一个input_file文本文件,然后再读取,,,,!!!
ofstream out_file("output_file.txt");//定义输入输出文件及其文件指针
if(!in_file||!out_file)
{
cerr<<"!!unable to open the necessary files.\n";//输出错误信息并清空输出缓存区
return -1;//这种方式比较温和吧。不如exit()那么暴力
}
istream_iterator<string>is(in_file);//定义is这个istream_iterator并将其绑定至in_file这个文件写入(指针)。
istream_iterator<string>eof;//定义eof这个istream_iterator指向读取的最后一个元素的下一个位置!!
vector<string>text;//定义string型vector(容器)---text
copy(is,eof,back_inserter(text));//复制操作,把文件里读取的数据扔给text这个容器
sort(text.begin(),text.end());//给text里的元素排个序
ostream_iterator<string>os(out_file," ");//定义os这个ostream_iterator并将其绑定至out_file这个文件输出(指针)
copy(text.begin(),text.end(),os);//复制操作,把text这个容器里的输入写入到文件中,每个写入的元素间有一个空格。
}
让我们看看程序运行结果:
程序运行↓
读取的文件↓
写入的文件↓
还是因为容器进行了排序,容器内组成的元素不同可能输出(写入)的次序就不同,所以输出(写入)的顺序是排完序后容器的元素(容器第一个元素w小于第二个元素n,故n开头的string型元素排在前)
再看个程序运行例子你就能明白(我所说的上面的内容):
读取的文件↓
写入到文件↓
明白了吧,不明白就别学了。