C++复习 10 关联容器
2007-10-22 23:24
344 查看
声明,所有的朋友,如果要转我的帖子,务必注明"作者:黑啤来源:CSDN博客"和具体的网络地址http://blog.csdn.net/nx500/archive/2007/10/22/1838229.aspx,并且我的所有博客内容,禁止任何形式的商业用途,请大家尊重我的劳动.谢谢!
目 录
十.关联容器(map/set/multimap/multiset).
001 pair类型.定义在utility头文件中.
pair<T1, T2> p;
pair<T1, T2> p(v1, v2);
make_pair(v1, v2);
p1 < p2
p1 == p2
p.first
p.second
创建pair和初始化.
pair<string, int> word_count;
pair<string, string> author("James", "Joyce");
typedef pair<string, string> Author;
Author proust("Marcel", "Proust");
pair对象的操作.
string firstBook;
if(author.first == "James" && author.second == "Joyce")
firstBook = "Stephen Hero";
生成pair对象.
string first, last;
while(cin>>first>>last){
author = make_pair(first, last);
}
// 也可以这样.
while(cin>>author.first>>author.second){
// ..
}
// 或者这样.
while(cin>>first>>last){
author = pair<string, string>(first, last);
}
002 关联容器.关联容器的元素根据键的次序排列,可以按照键的顺序访问容器元素,但元素的实际存放并不一定按照键的次序.
关联容器支持大部分普通容器的操作.但不提供front,push_front,pop_front,back,push_back以及pop_back操作.
支持的构造函数.
C<T> c;
C<T> c1(c2);
C<T> c(b, e);
关联容器不能通过容器大小来定义,因为这样就无法知道键所对应的值是什么.
支持容器的关系运算.
支持begin(), end(), rbegin(), rend()操作.
支持typedef和value_type类型.
支持swap和赋值操作,但不提供assign函数.
支持clear和erase操作,但关联容器的erase返回void类型.
不支持resize操作.
003 map类型.是键-值对的集合,通常可理解为关俩数组.可使用键作为下标来获取一个值.
#include <map>
using std::map;
键类型的约束:键类型必须有一个相关的比较函数,默认情况下为 < 操作符进行比较. 键类型必须是严格弱排序的.
定义map对象
map<k, v> m;
map<k, v> m(m2);
map<k, v> m(b, e);
map<string, int> word_count;
map定义的类型
map<k, v>::key_type
map<k, v>::mapped_type
map<k, v>::value_type 定义一个pair类型,第一个元素是const map<k, v>::key_type类型.
对map迭代器的解引用,将产生pair类型的对象.
map<string, int>::iterator map_it = word_count.begin();
cout << map_it->first;
cout << map_it->second;
// map_it->first = "new key"; // error, key类型是const的,不可以更改,只能采用删除和添加操作.
++map_it->second;
004 在map对象中添加元素.
使用下标,注意map于vector的区别,map下标操作返回的类型与迭代器解引用返回的类型不同.
map<string, int> word_count;
word_count["Anna"] = 1;
使用下标访问不存在的元素,将导致在map容器中添加一个新的元素,他的键为该下标值.使用这个特性使程序更加简练.
map <string, int> word_count;
string word;
while(cin > word){
++word_count[word];
}
005 在map中插入元素.
m.insert(e); 如果键e.first不再m中,则将e插入m中,如果m已经存在,保持m不变.
返回一个pari类型对象,包含一个指向键值为e.first元素的map迭代器,和一个bool类型对象,表示插入是否成功.
m.insert(begin,end) 返回void类型.
m.insert(iter, e) 如果键e.first不在m中,以iter为起点创建新元素的插入位置.返回以一个迭代器,指向m中具有给定键值的元素.
用insert代替下标添加元素.
word_count.insert(map<string, int>::value_type("Anna", 1));
简单一点的方法.
word_count.insert(make_pair("Anna", 1));
或者.
typedef map<string, int>::value_type valType;
word_count.insert(valType("Anna", 1));
检查insert操作的反回值.
map<string, int> word_count;
string word;
while(cin>>word){
pair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word,1));
if(!ret.second){
++ret.first->second;
}
}
006 查找并读取map中的元素.
m.count(k) 返回map中k出现的次数
m.find(k) 如果m容器中存在键值为k的元素,返回指向该元素的迭代器,不存在则"返回超出末端迭代起".
可以使用count检查map对象中是否存在某个键值.
int occurs = 0;
if(word_count.count("foobar")){ // 第一次查找
occurs = word_count["foobar"]; // 第二次查找
}
读取元素而不插入元素.
int occurs = 0;
map<string, int>::iterator it = word_count.find("foobar");
if (it != word_count.end()){
occurs = it->second;
}
007 从map对象中删除元素.
m.erase(k) 删除键值为k的元素,返回删除元素的个数.
m.erase(p) 从m中删除p所指向的元素,p必须是m中确实存在的元素,而且不能等于m.end(),返回void.
m.erase(b, e) 返回void.
string removal_word("foobar");
if (word_count.erase(removal_word)){
cout << "ok: " << removal_word << " removed" << endl;
}else{
cout << "opps: " << removal_word << " not found" << endl;
}
008 map对象的遍历.
map<string, int>::const_iterator map_it = word_count.begin();
while(map_it != word_count.end()){
cout << map_it->first << " occurs " << map_it->second << " times" << endl;
++map_it;
}
009 单词转换程序.将单词转换文件的内容存储在一个map容器中,将被替换的单词作为键,而用作替换的单词则作为其相应的值.
// 10009.cpp
#include <iostream>
#include <string>
#include <map>
#include <utility>
#include <fstream>
#include <sstream>
#include <stdexcept>
using std::map;
using std::string;
using std::pair;
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
using std::runtime_error;
// in作为文件指针,file存放文件名称,代开输入文件
ifstream& open_file(ifstream& in, const string &file)...{
// 清空文件指针的状态
in.close();
in.clear();
// open函数输入参数为字符串字面值
in.open(file.c_str());
return in;
}
// 单词转换
int main(int argc, char **argv)...{
map<string, string> trans_map; // 存放译码
string key, value; // 生成译码容器的辅助变量
// 判断输入参数是否符合规则
if(argc != 3)
cout << argv[0] << "<trans map filename> <input filename>" << endl;
// 定义map_file指针并打开之,读入生成对应的翻译表
ifstream map_file;
if(!open_file(map_file, argv[1]))
throw runtime_error("no transormation file");
while(map_file >> key >> value)
trans_map.insert(make_pair(key, value));
map_file.close();
// 定义input文件指针,并打开输入文件
ifstream input;
if(!open_file(input, argv[2]))
throw runtime_error("no input file");
// 每次从文件中读入一行
string line;
while(getline(input, line))...{
// 一次处理一行内的一个单词
istringstream stream(line);
string word;
bool firstword = true;
while(stream >> word)...{
// 查找译码,有译码输出译码,没有译码输出原文
map<string, string>::const_iterator map_it = trans_map.find(word);
if(map_it != trans_map.end())
word = map_it->second;
// 第一个单词前不输出空格
if(firstword)
firstword = false;
else
cout << " ";
cout << word;
}
cout << endl;
}
return 0;
}
transmap.txt文件的内容
'em them
cuz because
gratz grateful
i I
nah no
pos supposed
sez said
tanx thanks
wuz was
src.txt文件的内容
nah i sez tanx cuz i wuz pos to
not cuz i wuz gratz
// 编译及运行结果
heipi@Linux:~/Documents/CPP> g++ -o o 10009.cpp
heipi@Linux:~/Documents/CPP> ./o transmap.txt src.txt
no I said thanks because I was supposed to
not because I was grateful
heipi@Linux:~/Documents/CPP>
010 set类型容器只是单纯的键的集合.set容器中存储的键也必须是唯一的,而且不能修改.
set容器中,value_type不是pair类型,而是与key_type相同的类型.set没有定义mapped_type类型,也不支持下标操作.
定义set
set<int> iset;
添加元素
iset.insert(1);
int ia[] = {0, 2, 3, 4, 5};
iset.insert(ia, ia + 5); // 同map的insert函数一样,返回一个pair类型,second元素为bool类型
从set中获取元素(实质是判断元素是否在set中)
iset.find(1); // 返回指向元素1的const_iterator,也就是说不能直接修改元素的值,只能删除,添加
iset.find(-1); // 返回iset.end()
iset.count(1); // 返回1,表示set里有这个元素
iset.count(-1); // 返回0,表示set里没有这个元素
单词排除集算法
void restricted_wc(ifstream &remove_file, map<string, int> &word_count){
set<string> excluded;
string remove_word;
// 从remove_file文读取排除的单词,创建排除集合
while(remove_file >> remove_word){
excluded.insert(remove_word);
}
string word;
// 对于每个输入单词,统计不再排除集合中单词的个数
while(cin >> word){
if(!excluded.count(word))
++word_cound[word];
}
}
011 multiset和multimap类型允许一个键对应多个实例.multiset和multimap支持大部分set和map的操作.multimap不支持下标操作.
添加元素.
multimap<string, string> authors;
authors.insert(make_pir(string("Barth, John"), string("Sot-weed Factor")));
authors.insert(make_pir(string("Barth, John"), string("Lost in the funhouse")));
删除元素,返回删除元素的个数.
multimap<string, string>::size_type cnt = authors.erase(string(Barth, John"));
查找元素,有三种办法.首先要知道的是在multimap和multiset容器中,如果键对应多个实例,则这些实例在容器总将相邻存放.
使用count可以计算出某键出现的次数,用find返回迭代器指向相邻存放元素的第一个位置.
// 方案一
typedef multimap<string, string>::size_type sz_authors;
string search_item("Barth, John");
// 统计含有该键值元素的个数
sz_authors sz = authors.count(search_item);
multimap<string, string>::iterator it = authors.find(search_item);
// 输出所有元素
for(sz_authors cnt = 0; cnt != sz; +=cnt)
cout << iter->second << endl;
两个专用的操作
m.lower_bound(k) // 返回迭代器,指向键值不小于K的第一个元素,如果该键不再m中,返回该键应该被插入的第一个位置
m.upper_bound(k) // 返回迭代器,指向键值大于K的第一个元素
m.equal_range(k) // 返回pair对象,first元素是m.lower_bound(k),second元素是m.upper_bound(k)
// 方案二
typdef multimap<string, string>::iterator authors_it;
authors_it beg = authors.lower_bound(search_item);
authors_it end = authors.upper_bound(search_item);
// 如果返回的范围不是个空集,就说明有符合这个键值的元素
while(beg != end){
cout << beg->second << endl;
++beg;
}
// 方案三
pair<authors_it, authors_it> pos = authors.equal_range(search_item);
while(pos.first != pos.second){
cout << pos.first->second << endl;
++pos.first;
}
012 容器的综合应用,文本查询程序.
功能描述:程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在的行.
如果某单词在同一行中多次出现,程序将只显式改行一次.行好按升序显式.
需求分解:
1.允许用户指明要处理的文件名字.
2.必须将没一行分解为各个单词,并记录每个单词所在的所有行,输出行号时,保证以升序输出.
3.对特定单词的查询将返回该单词的所哟行的行号.
4.输出某单词所在的行文本时,程序必须能根据给定的行号从文件中获取相应的行.
定义数据结构.
1.使用一个vector<string>类型的对象存储整个输入文件的副本.输入文件的每一行是该vector对象的一个元素.
2.将每个单词所在的行号存在一个set容器中,这样可以确保每行只有一个条目,而且行号将自动按升序排列.
3.使用一个map容器,将每个单词与一个set容器对象关联起来.
综合起来,我们需要定义一个TextQuery类,它含有两个数据成员,存储输入文件的vector对象,以及一个map容器对象.
操作接口.
1.read_file成员函数,形参是一个ifstream&类型的对象.该函数每次从文件读入一行,保存在vector<string>中.
读入完毕后,创建关联每个单词及其所在行号的map容器.这是一个内部接口,不对外开放.定义两个内部接口实现以上功能.
store_file函数读入文件,将内容存入vector容器;build_map函数分解每一行,创建map容器.
3.run_query成员函数,形参为一个string类型的对象,返回一个set对象,包含该string对象的多有行的行号.
3.text_line成员函数,形参为一个行号,返回输入文本中该行号对应的文本行.
程序代码.
// TextQuery.h
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
class TextQuery...{
public:
// 定义公共的变量类型
typedef std::vector<std::string>::size_type line_no;
// 读入文件,将内容存入vector容器;创建map容器
void read_file(std::ifstream& is)...{
store_file(is);
build_map();
}
// 返回一个set对象,包含该string对象的多有行的行号.
std::set<line_no> run_query(const std::string &) const;
// 返回输入文本中该行号对应的文本行.
std::string text_line(line_no) const;
private:
// 按行存放文件
std::vector<std::string> lines_of_text;
// 单词和单词所在行号的集合的容器
std::map<std::string, std::set<line_no> >word_map;
void store_file(std::ifstream&); // 将文件存入lines_of_text容器中
void build_map(); // 生成<单词, 所在行集合>容器
};
#endif
// TextQuery.cpp
#include <string>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <set>
#include <map>
#include <vector>
#include "TextQuery.h"
using std::string;
using std::ifstream;
using std::istringstream;
using std::out_of_range;
using std::map;
using std::set;
using std::vector;
// 读入需要查询的文件
void TextQuery::store_file(ifstream& is)...{
string textline;
while(getline(is, textline))
lines_of_text.push_back(textline);
}
// 创建map容器
void TextQuery::build_map()...{
for(line_no line_num = 0; line_num != lines_of_text.size(); ++line_num)...{
istringstream line(lines_of_text[line_num]);
string word;
while(line >> word)
word_map[word].insert(line_num);
}
}
// 返回一个set对象,包含该string对象的多有行的行号.
set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const...{
map<string, set<line_no> >::const_iterator loc = word_map.find(query_word);
if(loc == word_map.end())
return set<line_no>();
else
return loc->second;
}
// 返回输入文本中该行号对应的文本行.
string TextQuery::text_line(line_no line) const...{
if(line < lines_of_text.size())
return lines_of_text[line];
throw out_of_range("line number out of range");
}
// 10012.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <set>
#include "TextQuery.h"
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::ifstream;
using std::set;
// 创建复数形式
string make_plural(size_t ctr, const string &word, const string &ending)...{
return (ctr == 1) ? word : word + ending;
}
// in作为文件指针,file存放文件名称,代开输入文件
ifstream& open_file(ifstream& in, const string &file)...{
// 清空文件指针的状态
in.close();
in.clear();
// open函数输入参数为字符串字面值
in.open(file.c_str());
return in;
}
// 输出
void print_results(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery &file)...{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();
cout << " " << sought << " occurs "
<< size << " " << make_plural(size, "time", "s") << endl;
line_nums::const_iterator it = locs.begin();
for( ; it != locs.end(); ++it)...{
cout << " (line "
<< (*it) + 1 << ")"
<< file.text_line(*it) << endl;
}
}
int main(int argc, char **argv)...{
ifstream infile;
// 如果没有给定输入文件或者输入文件打不开,提示错误信息并结束程序
if (argc < 2 || !open_file(infile, argv[1]))...{
cerr << "No input file!" << endl;
return EXIT_FAILURE;
}
// 将文件读入内存并创建map表,创建结束后关闭文件指针
TextQuery tq;
tq.read_file(infile);
infile.close();
infile.clear();
// 查询
while(true)...{
cout << "enter word to look for, or q to quit:";
string s;
cin >> s;
if (!cin || s == "q")
break;
set<TextQuery::line_no> locs = tq.run_query(s);
print_results(locs, s, tq);
}
return 0;
}
目 录
十.关联容器(map/set/multimap/multiset).
001 pair类型.定义在utility头文件中.
pair<T1, T2> p;
pair<T1, T2> p(v1, v2);
make_pair(v1, v2);
p1 < p2
p1 == p2
p.first
p.second
创建pair和初始化.
pair<string, int> word_count;
pair<string, string> author("James", "Joyce");
typedef pair<string, string> Author;
Author proust("Marcel", "Proust");
pair对象的操作.
string firstBook;
if(author.first == "James" && author.second == "Joyce")
firstBook = "Stephen Hero";
生成pair对象.
string first, last;
while(cin>>first>>last){
author = make_pair(first, last);
}
// 也可以这样.
while(cin>>author.first>>author.second){
// ..
}
// 或者这样.
while(cin>>first>>last){
author = pair<string, string>(first, last);
}
002 关联容器.关联容器的元素根据键的次序排列,可以按照键的顺序访问容器元素,但元素的实际存放并不一定按照键的次序.
关联容器支持大部分普通容器的操作.但不提供front,push_front,pop_front,back,push_back以及pop_back操作.
支持的构造函数.
C<T> c;
C<T> c1(c2);
C<T> c(b, e);
关联容器不能通过容器大小来定义,因为这样就无法知道键所对应的值是什么.
支持容器的关系运算.
支持begin(), end(), rbegin(), rend()操作.
支持typedef和value_type类型.
支持swap和赋值操作,但不提供assign函数.
支持clear和erase操作,但关联容器的erase返回void类型.
不支持resize操作.
003 map类型.是键-值对的集合,通常可理解为关俩数组.可使用键作为下标来获取一个值.
#include <map>
using std::map;
键类型的约束:键类型必须有一个相关的比较函数,默认情况下为 < 操作符进行比较. 键类型必须是严格弱排序的.
定义map对象
map<k, v> m;
map<k, v> m(m2);
map<k, v> m(b, e);
map<string, int> word_count;
map定义的类型
map<k, v>::key_type
map<k, v>::mapped_type
map<k, v>::value_type 定义一个pair类型,第一个元素是const map<k, v>::key_type类型.
对map迭代器的解引用,将产生pair类型的对象.
map<string, int>::iterator map_it = word_count.begin();
cout << map_it->first;
cout << map_it->second;
// map_it->first = "new key"; // error, key类型是const的,不可以更改,只能采用删除和添加操作.
++map_it->second;
004 在map对象中添加元素.
使用下标,注意map于vector的区别,map下标操作返回的类型与迭代器解引用返回的类型不同.
map<string, int> word_count;
word_count["Anna"] = 1;
使用下标访问不存在的元素,将导致在map容器中添加一个新的元素,他的键为该下标值.使用这个特性使程序更加简练.
map <string, int> word_count;
string word;
while(cin > word){
++word_count[word];
}
005 在map中插入元素.
m.insert(e); 如果键e.first不再m中,则将e插入m中,如果m已经存在,保持m不变.
返回一个pari类型对象,包含一个指向键值为e.first元素的map迭代器,和一个bool类型对象,表示插入是否成功.
m.insert(begin,end) 返回void类型.
m.insert(iter, e) 如果键e.first不在m中,以iter为起点创建新元素的插入位置.返回以一个迭代器,指向m中具有给定键值的元素.
用insert代替下标添加元素.
word_count.insert(map<string, int>::value_type("Anna", 1));
简单一点的方法.
word_count.insert(make_pair("Anna", 1));
或者.
typedef map<string, int>::value_type valType;
word_count.insert(valType("Anna", 1));
检查insert操作的反回值.
map<string, int> word_count;
string word;
while(cin>>word){
pair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word,1));
if(!ret.second){
++ret.first->second;
}
}
006 查找并读取map中的元素.
m.count(k) 返回map中k出现的次数
m.find(k) 如果m容器中存在键值为k的元素,返回指向该元素的迭代器,不存在则"返回超出末端迭代起".
可以使用count检查map对象中是否存在某个键值.
int occurs = 0;
if(word_count.count("foobar")){ // 第一次查找
occurs = word_count["foobar"]; // 第二次查找
}
读取元素而不插入元素.
int occurs = 0;
map<string, int>::iterator it = word_count.find("foobar");
if (it != word_count.end()){
occurs = it->second;
}
007 从map对象中删除元素.
m.erase(k) 删除键值为k的元素,返回删除元素的个数.
m.erase(p) 从m中删除p所指向的元素,p必须是m中确实存在的元素,而且不能等于m.end(),返回void.
m.erase(b, e) 返回void.
string removal_word("foobar");
if (word_count.erase(removal_word)){
cout << "ok: " << removal_word << " removed" << endl;
}else{
cout << "opps: " << removal_word << " not found" << endl;
}
008 map对象的遍历.
map<string, int>::const_iterator map_it = word_count.begin();
while(map_it != word_count.end()){
cout << map_it->first << " occurs " << map_it->second << " times" << endl;
++map_it;
}
009 单词转换程序.将单词转换文件的内容存储在一个map容器中,将被替换的单词作为键,而用作替换的单词则作为其相应的值.
// 10009.cpp
#include <iostream>
#include <string>
#include <map>
#include <utility>
#include <fstream>
#include <sstream>
#include <stdexcept>
using std::map;
using std::string;
using std::pair;
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
using std::runtime_error;
// in作为文件指针,file存放文件名称,代开输入文件
ifstream& open_file(ifstream& in, const string &file)...{
// 清空文件指针的状态
in.close();
in.clear();
// open函数输入参数为字符串字面值
in.open(file.c_str());
return in;
}
// 单词转换
int main(int argc, char **argv)...{
map<string, string> trans_map; // 存放译码
string key, value; // 生成译码容器的辅助变量
// 判断输入参数是否符合规则
if(argc != 3)
cout << argv[0] << "<trans map filename> <input filename>" << endl;
// 定义map_file指针并打开之,读入生成对应的翻译表
ifstream map_file;
if(!open_file(map_file, argv[1]))
throw runtime_error("no transormation file");
while(map_file >> key >> value)
trans_map.insert(make_pair(key, value));
map_file.close();
// 定义input文件指针,并打开输入文件
ifstream input;
if(!open_file(input, argv[2]))
throw runtime_error("no input file");
// 每次从文件中读入一行
string line;
while(getline(input, line))...{
// 一次处理一行内的一个单词
istringstream stream(line);
string word;
bool firstword = true;
while(stream >> word)...{
// 查找译码,有译码输出译码,没有译码输出原文
map<string, string>::const_iterator map_it = trans_map.find(word);
if(map_it != trans_map.end())
word = map_it->second;
// 第一个单词前不输出空格
if(firstword)
firstword = false;
else
cout << " ";
cout << word;
}
cout << endl;
}
return 0;
}
transmap.txt文件的内容
'em them
cuz because
gratz grateful
i I
nah no
pos supposed
sez said
tanx thanks
wuz was
src.txt文件的内容
nah i sez tanx cuz i wuz pos to
not cuz i wuz gratz
// 编译及运行结果
heipi@Linux:~/Documents/CPP> g++ -o o 10009.cpp
heipi@Linux:~/Documents/CPP> ./o transmap.txt src.txt
no I said thanks because I was supposed to
not because I was grateful
heipi@Linux:~/Documents/CPP>
010 set类型容器只是单纯的键的集合.set容器中存储的键也必须是唯一的,而且不能修改.
set容器中,value_type不是pair类型,而是与key_type相同的类型.set没有定义mapped_type类型,也不支持下标操作.
定义set
set<int> iset;
添加元素
iset.insert(1);
int ia[] = {0, 2, 3, 4, 5};
iset.insert(ia, ia + 5); // 同map的insert函数一样,返回一个pair类型,second元素为bool类型
从set中获取元素(实质是判断元素是否在set中)
iset.find(1); // 返回指向元素1的const_iterator,也就是说不能直接修改元素的值,只能删除,添加
iset.find(-1); // 返回iset.end()
iset.count(1); // 返回1,表示set里有这个元素
iset.count(-1); // 返回0,表示set里没有这个元素
单词排除集算法
void restricted_wc(ifstream &remove_file, map<string, int> &word_count){
set<string> excluded;
string remove_word;
// 从remove_file文读取排除的单词,创建排除集合
while(remove_file >> remove_word){
excluded.insert(remove_word);
}
string word;
// 对于每个输入单词,统计不再排除集合中单词的个数
while(cin >> word){
if(!excluded.count(word))
++word_cound[word];
}
}
011 multiset和multimap类型允许一个键对应多个实例.multiset和multimap支持大部分set和map的操作.multimap不支持下标操作.
添加元素.
multimap<string, string> authors;
authors.insert(make_pir(string("Barth, John"), string("Sot-weed Factor")));
authors.insert(make_pir(string("Barth, John"), string("Lost in the funhouse")));
删除元素,返回删除元素的个数.
multimap<string, string>::size_type cnt = authors.erase(string(Barth, John"));
查找元素,有三种办法.首先要知道的是在multimap和multiset容器中,如果键对应多个实例,则这些实例在容器总将相邻存放.
使用count可以计算出某键出现的次数,用find返回迭代器指向相邻存放元素的第一个位置.
// 方案一
typedef multimap<string, string>::size_type sz_authors;
string search_item("Barth, John");
// 统计含有该键值元素的个数
sz_authors sz = authors.count(search_item);
multimap<string, string>::iterator it = authors.find(search_item);
// 输出所有元素
for(sz_authors cnt = 0; cnt != sz; +=cnt)
cout << iter->second << endl;
两个专用的操作
m.lower_bound(k) // 返回迭代器,指向键值不小于K的第一个元素,如果该键不再m中,返回该键应该被插入的第一个位置
m.upper_bound(k) // 返回迭代器,指向键值大于K的第一个元素
m.equal_range(k) // 返回pair对象,first元素是m.lower_bound(k),second元素是m.upper_bound(k)
// 方案二
typdef multimap<string, string>::iterator authors_it;
authors_it beg = authors.lower_bound(search_item);
authors_it end = authors.upper_bound(search_item);
// 如果返回的范围不是个空集,就说明有符合这个键值的元素
while(beg != end){
cout << beg->second << endl;
++beg;
}
// 方案三
pair<authors_it, authors_it> pos = authors.equal_range(search_item);
while(pos.first != pos.second){
cout << pos.first->second << endl;
++pos.first;
}
012 容器的综合应用,文本查询程序.
功能描述:程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在的行.
如果某单词在同一行中多次出现,程序将只显式改行一次.行好按升序显式.
需求分解:
1.允许用户指明要处理的文件名字.
2.必须将没一行分解为各个单词,并记录每个单词所在的所有行,输出行号时,保证以升序输出.
3.对特定单词的查询将返回该单词的所哟行的行号.
4.输出某单词所在的行文本时,程序必须能根据给定的行号从文件中获取相应的行.
定义数据结构.
1.使用一个vector<string>类型的对象存储整个输入文件的副本.输入文件的每一行是该vector对象的一个元素.
2.将每个单词所在的行号存在一个set容器中,这样可以确保每行只有一个条目,而且行号将自动按升序排列.
3.使用一个map容器,将每个单词与一个set容器对象关联起来.
综合起来,我们需要定义一个TextQuery类,它含有两个数据成员,存储输入文件的vector对象,以及一个map容器对象.
操作接口.
1.read_file成员函数,形参是一个ifstream&类型的对象.该函数每次从文件读入一行,保存在vector<string>中.
读入完毕后,创建关联每个单词及其所在行号的map容器.这是一个内部接口,不对外开放.定义两个内部接口实现以上功能.
store_file函数读入文件,将内容存入vector容器;build_map函数分解每一行,创建map容器.
3.run_query成员函数,形参为一个string类型的对象,返回一个set对象,包含该string对象的多有行的行号.
3.text_line成员函数,形参为一个行号,返回输入文本中该行号对应的文本行.
程序代码.
// TextQuery.h
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
class TextQuery...{
public:
// 定义公共的变量类型
typedef std::vector<std::string>::size_type line_no;
// 读入文件,将内容存入vector容器;创建map容器
void read_file(std::ifstream& is)...{
store_file(is);
build_map();
}
// 返回一个set对象,包含该string对象的多有行的行号.
std::set<line_no> run_query(const std::string &) const;
// 返回输入文本中该行号对应的文本行.
std::string text_line(line_no) const;
private:
// 按行存放文件
std::vector<std::string> lines_of_text;
// 单词和单词所在行号的集合的容器
std::map<std::string, std::set<line_no> >word_map;
void store_file(std::ifstream&); // 将文件存入lines_of_text容器中
void build_map(); // 生成<单词, 所在行集合>容器
};
#endif
// TextQuery.cpp
#include <string>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <set>
#include <map>
#include <vector>
#include "TextQuery.h"
using std::string;
using std::ifstream;
using std::istringstream;
using std::out_of_range;
using std::map;
using std::set;
using std::vector;
// 读入需要查询的文件
void TextQuery::store_file(ifstream& is)...{
string textline;
while(getline(is, textline))
lines_of_text.push_back(textline);
}
// 创建map容器
void TextQuery::build_map()...{
for(line_no line_num = 0; line_num != lines_of_text.size(); ++line_num)...{
istringstream line(lines_of_text[line_num]);
string word;
while(line >> word)
word_map[word].insert(line_num);
}
}
// 返回一个set对象,包含该string对象的多有行的行号.
set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const...{
map<string, set<line_no> >::const_iterator loc = word_map.find(query_word);
if(loc == word_map.end())
return set<line_no>();
else
return loc->second;
}
// 返回输入文本中该行号对应的文本行.
string TextQuery::text_line(line_no line) const...{
if(line < lines_of_text.size())
return lines_of_text[line];
throw out_of_range("line number out of range");
}
// 10012.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <set>
#include "TextQuery.h"
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::string;
using std::ifstream;
using std::set;
// 创建复数形式
string make_plural(size_t ctr, const string &word, const string &ending)...{
return (ctr == 1) ? word : word + ending;
}
// in作为文件指针,file存放文件名称,代开输入文件
ifstream& open_file(ifstream& in, const string &file)...{
// 清空文件指针的状态
in.close();
in.clear();
// open函数输入参数为字符串字面值
in.open(file.c_str());
return in;
}
// 输出
void print_results(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery &file)...{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();
cout << " " << sought << " occurs "
<< size << " " << make_plural(size, "time", "s") << endl;
line_nums::const_iterator it = locs.begin();
for( ; it != locs.end(); ++it)...{
cout << " (line "
<< (*it) + 1 << ")"
<< file.text_line(*it) << endl;
}
}
int main(int argc, char **argv)...{
ifstream infile;
// 如果没有给定输入文件或者输入文件打不开,提示错误信息并结束程序
if (argc < 2 || !open_file(infile, argv[1]))...{
cerr << "No input file!" << endl;
return EXIT_FAILURE;
}
// 将文件读入内存并创建map表,创建结束后关闭文件指针
TextQuery tq;
tq.read_file(infile);
infile.close();
infile.clear();
// 查询
while(true)...{
cout << "enter word to look for, or q to quit:";
string s;
cin >> s;
if (!cin || s == "q")
break;
set<TextQuery::line_no> locs = tq.run_query(s);
print_results(locs, s, tq);
}
return 0;
}
相关文章推荐
- C++ Primer Chapter 10 关联容器之set & mutimap
- C++ Primer Chapter 10 关联容器之容器的综合应用:文本查询程序
- C++ Primer Chapter 10 关联容器之map
- c++有序关联容器中键类型的约束
- C++map关联容器
- C++中的关联容器
- C++中关联容器map和set使用说明
- c\c++复习基础要点10---智能指针
- [C++ 从入门到放弃-10]C++STL之bitset位集合容器
- C++关联容器类:集合和多重集合类、映射和多重映射类
- C++学习基础四——顺序容器和关联容器
- C++关联容器
- C++ 关联容器
- C++容器(二):关联容器简介
- C++学习笔记【第二部分第十一章:关联容器】
- 2011/10/05~10/06 c++复习与学习
- C++ 标准库关联容器
- C++学习笔记-关联容器
- C++ 11 特性:关联容器map、set的使用
- C++ 关联容器之map插入相同键元素与查找元素操作