您的位置:首页 > 编程语言 > C语言/C++

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;


}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: