C++举出与技巧【set容器、multimap 和 multiset】

来源:互联网 发布:js视频 编辑:程序博客网 时间:2024/05/16 12:48
 

set 容器只是单纯的键的集合。

除了两种例外情况,set 容器支持大部分的 map 操作,包括下面几种:
• 通用的容器操作。
• 构造函数。
• insert 操作。
• count 和 find 操作。
• erase 操作。
两种例外包括set 不支持下标操作符,而且没有定义 mapped_type 类型。在 set 容器中,value_type 不是 pair 类型,而是与 key_type 相同的类型。它们指的都是 set 中存储的元素类型。这一差别也体现了 set 存储的元素仅仅是键,而没有所关联的值。与 map 一样,set 容器存储的键也必须唯一,而且不能修改。

例程

// define a vector with 20 elements, holding two copies of each number
from 0 to 9
vector<int> ivec;
for (vector<int>::size_type i = 0; i != 10; ++i) {
ivec.push_back(i);
ivec.push_back(i); // duplicate copies of each number
}
// iset holds unique elements from ivec
set<int> iset(ivec.begin(), ivec.end());
cout << ivec.size() << endl; // prints 20
cout << iset.size() << endl; // prints 10
首先创建了一个名为 ivec 的 int 型 vector 容器,存储 20 个元素:0-9(包括 9)中每个整数都出现了两次。然后用 ivec 中所有的元素初始化一个int 型的 set 容器。则这个 set 容器仅有 10 个元素:ivec 中不相同的各个元素。

set<string> set1; // empty set
set1.insert("the"); // set1 now has one element
set1.insert("and"); // set1 now has two elements

例程:set<int> iset2; // empty set
iset2.insert(ivec.begin(), ivec.end()); // iset2 has 10
elements
与 map 容器的操作一样,带有一个键参数的 insert 版本返回 pair 类型对象,包含一个迭代器和一个 bool 值,迭代器指向拥有该键的元素,而 bool 值表明是否添加了元素。使用迭代器对的 insert 版本返回 void 类型。

find和count:

iset.find(1) // returns iterator that refers to the element with key == 1
iset.find(11) // returns iterator == iset.end()
iset.count(1) // returns 1
iset.count(11) // returns 0

set 中的键也为 const。在获得指向 set 中某元素的迭代器后,只能对其做读操作,而不能做写操作。

可删除指定文件中所有的单词(即该文件记录的是排除集)。也
即,我们的单词统计程序只对那些不在排除集中的单词进行统计。使用 set 和
map 容器,可以简单而直接地实现该功能:
void restricted_wc(ifstream &remove_file,map<string, int> &word_count)
{
set<string> excluded; // set to hold words we'll ignore
string remove_word;
while (remove_file >> remove_word)
excluded.insert(remove_word);
// read input and keep a count for words that aren't in the exclusion set
string word;
while (cin >> word)
// increment counter only if the word is not in excluded
if (!excluded.count(word))
++word_count[word];
}

++word_count[word];的效果是:如果 word 还没出现过,则将它插入到 word_count 中,并在插入元素后,将它关联的值初始化为 0。然后不管是否插入了新元素,相应元素的值都加 1。

multiset 和 multimap类型则允许一个键对应多个实例。

例程:定义一个 multimap 容器对象将作者映射到他们所写的书的书名上。这样的映射可为一个作者存储多个条目:
// adds first element with key Barth
authors.insert(make_pair(string("Barth, John"),string("Sot-Weed Factor")));
// ok: adds second element with key Barth
authors.insert(make_pair(string("Barth, John"),string("Lost in the Funhouse")));

带有一个键参数的 erase 版本将删除拥有该键的所有元素,并返回删除元素的个数。而带有一个或一对迭代器参数的版本只删除指定的元素,并返回 void类型:
multimap<string, string> authors;
string search_item("Kazuo Ishiguro");
// erase all elements with this key; returns number of elements removed
multimap<string, string>::size_type cnt =authors.erase(search_item);

在 multimap 和 multiset 容器中,如果某个键对应多个实例,则这些实例在容器中将相邻存放。

寻找元素:使用 find 和 count 可有效地解决刚才的问题。count 函数求出某键出现的次数,而 find 操作则返回一个迭代器,指向第一个拥有正在查找的键的实例:
// author we'll look for
string search_item("Alain de Botton");
// how many entries are there for this author
typedef multimap<string, string>::size_type sz_type;
sz_type entries = authors.count(search_item);
// get iterator to the first entry for this author
multimap<string,string>::iterator iter =authors.find(search_item);
// loop through the number of entries there are for this author
for (sz_type cnt = 0; cnt != entries; ++cnt, ++iter) cout <<iter->second << endl;

// print each title
首先,调用 count 确定某作者所写的书籍数目,然后调用 find 获得指向第一个该键所关联的元素的迭代器。for 循环迭代的次数依赖于 count 返回的值。在特殊情况下,如果 count 返回 0 值,则该循环永不执行。

另一个更优雅简洁的方法是使用两个未曾见过的关联容器的操作:lower_bound 和 upper_bound。下表列出的这些操作适用于所有的关联容器,也可用于普通的 map 和 set 容器,但更常用于 multimap 和 multiset。所有这些操作都需要传递一个键,并返回一个迭代器。

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)

使用这些操作,可如下重写程序:
// definitions of authors and search_item as above
// beg and end denote range of elements for this author
typedef multimap<string, string>::iterator authors_it;
authors_it beg = authors.lower_bound(search_item),
end = authors.upper_bound(search_item);
// loop through the number of entries there are for this author
while (beg != end) {
cout << beg->second << endl; // print each title
++beg;
}
若该键没有关联的元素,则 lower_bound 和 upper_bound 返回相同的迭代器:都指向同一个元素或同时指向 multimap 的超出末端位置。它们都指向在保持容器元素顺序的前提下该键应被插入的位置。
解决上述问题更直接的方法是:调用 equal_range 函数来取代调用 upper_bound 和 lower_bound 函数。equal_range 函数返回存储一对迭代器的 pair 对象。如果该值存在,则 pair 对象中的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一位置如果找不到匹配的元素,则 pair 对象中的两个迭代器都将指向此键应该插入的位置。
使用 equal_range 函数再次修改程序:
// definitions of authors and search_item as above
// pos holds iterators that denote range of elements for this key
pair<authors_it, authors_it> pos = authors.equal_range(search_item);
// loop through the number of entries there are for this author
while (pos.first != pos.second) {
cout << pos.first->second << endl; // print each title
++pos.first;
}