12、C++ Primer 4th 笔记,关联容器(2)

时间:2022-10-11 00:41:29

1map set 容器中,一个键只能对应一个实例。multimapmultiset类型允许一个键对应多个实例。其支持的操作分别与mapset的操作相同,只有一个例外,multimap不支持下标运算。setmultiset专门用于存储键。

2、关联容器 map set 的元素是按顺序存储的。而 multimap multset 也一样。因此,在 multimap multiset 容器中,如果某个键对应多个实例,则这些实例在容器中将相邻存放。迭代遍历 multimap multiset 容器时,可保证依次返回特定键所关联的所有元素。

3、在multimapmultiset中寻找元素时,一般有以下三种方法:

1)使用 find count count 函数求出某键出现的次数,而 find 操作则返回一个迭代器,指向第一个拥有正在查找的键的实例。

2)用标准库提供的迭代器

m.lower_bound(k)

返回一个迭代器,指向键不小于 k 的第一个元素

m.upper_bound(k)

返回一个迭代器,指向键大于 k 的第一个元素

m.equal_range(k)

返回一个迭代器的 pair 对象它的 first 成员等价于m.lower_bound(k)。而 second 成员则等价于 m.upper_bound(k)

    若该键没有关联的元素,则 lower_bound upper_bound 返回相同的迭代

器:都指向同一个元素或同时指向 multimap 的超出末端位置。它们都指向在保

持容器元素顺序的前提下该键应被插入的位置。

4、一个查找文本的例子

#include "map"
#include "set"
#include "vector"
#include "string"
#include "fstream"
#include "iostream"
#include "sstream"
using namespace std;

class TextQuery
{
public:
typedef std::vector<std::string>::size_type line_no;
void read_file(std::ifstream &is) //读取文件,构造内部数据结构
{
store_file(is);
build_map();
}
std::set<line_no> run_query(const std::string&) const; //执行查找
std::string text_line(line_no) const; //返回找到单词的该行文本
private:
void store_file(std::ifstream&); //存储文件
void build_map(); //将每个单词与相关联的行号建立映射
std::vector<std::string> lines_of_text; //存储原文件的每一行
std::map< std::string, std::set<line_no> > word_map; //映射结构
};

void TextQuery::store_file(std::ifstream &is)
{
string textline;
while(getline(is, textline))
{
lines_of_text.push_back(textline);
}
}

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);
//word_map.insert(make_pair(word, line_num));
//word_map.insert(map<std::string, line_no>::value_type(word, line_no));
}
}
}

std::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>(); //not found, return empty set
else
return loc->second;
}

std::string TextQuery::text_line(line_no line) const
{
if (line < lines_of_text.size())
return lines_of_text[line];
else
throw std::out_of_range("line number out of range");
}

ifstream& open_file(ifstream &in, const string &file)
{
in.close(); // close in case it was already open
in.clear(); // clear any existing errors
// if the open fails, the stream will be in an invalid state
in.open(file.c_str()); // open the file we were given
return in; // condition state is good if open succeeded
}

string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr == 1) ? word : word + ending;
}

void printf_resluts(const set<TextQuery::line_no> &locs, const std::string &sought, const TextQuery &file)
{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();
cout << "\n" << sought << "occurs "
<< size << make_plural(size, "time", "s")
<< endl;
line_nums::const_iterator it = locs.begin();
for (; it != locs.end(); it++)
{
cout << "\t(line"
<< (*it) + 1 << ")"
<< file.text_line(*it)
<< endl;
}
}

int main(int argc, char **argv)
{
ifstream infile("C:\\1.txt");
/*if (argc < 2 || !open_file(infile, argv[1]))
{
cerr << "No input file" << endl;
return EXIT_FAILURE;
}*/

TextQuery tq;
tq.read_file(infile);

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);
printf_resluts(locs, s, tq);
}
return 0;
}

注意上面例子中:

word_map[word].insert(line_num);
不能替换成如下两种形式
//word_map.insert(make_pair(word, line_num));
//word_map.insert(map<std::string, line_no>::value_type(word, line_no));

因为make_pair的两个实参必须是具体的值,而不能是变量。

参考:

[1] http://blog.163.com/zhoumhan_0351/blog/static/399542272010227112325224/

http://blog.163.com/zhoumhan_0351/blog/static/39954227201032392545410/

http://blog.163.com/zhoumhan_0351/blog/static/399542272010229828061/

http://blog.163.com/zhoumhan_0351/blog/static/39954227201038102838349/

http://blog.163.com/zhoumhan_0351/blog/static/399542272010396030501/

http://blog.163.com/zhoumhan_0351/blog/static/39954227201039112031737/

http://blog.163.com/zhoumhan_0351/blog/static/39954227201022994439573/