C++ Primer学习之(10)——关联容器

来源:互联网 发布:keep软件 编辑:程序博客网 时间:2024/04/30 16:39

P466:

关联容器通过键(key)存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。

map的元素以键-值对的形式组织;

set仅包含一个键,并且有效地支持关于某个键是否存在的查询。

pair,该类型在utility头文件中定义。

pair类型的使用相当繁琐,因此,如果需要定义多个相同的pair类型对象,可以考虑利用typedef简化其声明:

typedef pair<string, string> Author;Author proust("Marcel", "Proust");Author joyce("James", "Joyce");
除了构造函数,标准库还定义了一个make_pair函数,由传递给它的两个实参生成一个新的pair对象。

pair<string, string> next_auth;string first, last;// generate a pair from first and lastnext_auth = make_pair(first, last); 
此操作等价于:

// use pair constructor to make first and last into a pairnext_auth = pair<string, string>(first, last);
注:之前读代码读到一切关于pair和make_pair的代码都觉得头大,读完这段了然。


P470:

map类型通常可理解为关联数组(associative array):可是用键作为下标来获取一个值,正如内置数组类型一样。而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置来获取。

// count number of times each word occurs in the inputmap<string, int> word_count; // empty map from string to int
在学习map接口时,需谨记value_type是pair类型,它的值成员可以修改,但键成员是 const类型不能修改。

对迭代器进行解引用将获得一个引用,指向容器中一个value_type类型的值。对于map容器,其value_type是pair类型:

// *map_it is a reference to a pair<const string, int> objectcout << map_it->first; // prints the key for this elementcout << " " << map_it->second; // prints the value of the elementmap_it->first = "new key"; // error: key is const++map_it->second; // ok: we can change value through an iterator
map类额外定义了两种类型:key_typemapped_type,以获取得类型。


P474:

使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素将导致在map容器中添加一个新元素,它的键即为该下标值。

map<string, int> word_count; // empty map// insert default initialized element with key Anna; then assign 1 to its valueword_count["Anna"] = 1;
map迭代器返回value_type类型的值——包含const key_typemapped_type类型成员的pair对象;下标操作符则返回一个mapped_type类型的值

对于map容器,如果下标所表示的键在容器中不存在,则添加新元素,这一特性可使程序惊人地简练:

// count number of times each word occurs in the inputmap<string, int> word_count; // empty map from string to intstring word;while (cin >> word)++word_count[word];
注:面试里经常会出现的统计问题,如果下次再碰到了,一定试试用map来解。


P477:

直接使用insert成员插入元素:

// if Anna not already in word_count, inserts new elements with value 1word_count.insert(map<string, int>::value_type("Anna", 1));
传递给insert的实参相当笨拙,可使用两种方法简化:使用make_pair:

word_count.insert(make_pair("Anna"), 1);
或使用typedef:

typedef map<string, int>::value_type valType;word_count.insert(valType("Anna", 1));
带有一个键-值pair形参的insert版本将返回一个值:包含一个迭代器和一个bool值得pair对象,其中迭代器指向map中具有相应键的元素,而bool值则表示是否插入了该元素。

下面是使用insert重写的单词统计程序:

// count number of times each word occurs in the inputmap<string, int> word_count; // empty map from string to intstring word;while (cin >> word){// inserts element with key equal to word and value 1;// if word already in word_count, insert does nothingpair<map<string, int>::iterator, bool> ret = word_count.insert(make_pair(word, 1));if (!ret.second) // word already in word_count{++ret.first->second; // increment counter}}

P479:

下标操作符给出了读取一个值最简单的方法:

map<string, int> word_count;int occurs = word_count["foobar"];
但是下标存在一个很危险的副作用:如果该键不在map容器中,那么下标操作会插入一个具有改键的新元素。

map容器提供了两个操作:count和find,用于检查某个键是否存在而不会插入该键。

m.count(k):返回m中k的出现次数。对于map对象,count成员的返回值只能是0或1

m.find(k):如果m容器中存在按k索引的元素,则返回该元素的迭代器。如果不存在,则返回超出末端迭代器。


P482:

map对象的迭代编译

// get iterator positioned on the first elementmap<string, int>::const_iterator map_it = word_count.begin();// for each element in the mapwhile (map_it != word_count.end()){// print the element key, value pairscout << map_it->first << " occurs"<< map_it->second << " times" << endl;++map_it; // increment iterator to denote the next element}


P486:

set容器只是单纯地键的集合。在set容器中,value_type不是pair类型,而是与key_type相同的类型。set容器中的每个键都只能对应一个元素。

// define a vector with 20 elements, holding two copied of each number from 0 to 9vector<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 ivecset<int> iset(ivec.begin(), ivec.end());cout << ivec.size() << endl; // prints 20cout << iset.size() << endl; // prints 10

P490:

在multimap和multiset中查找元素

multiset和multimap类型允许一个键对应多个实例。例如,在电话簿中,每个人可能有单独的电话号码列表。在作者的文章集中,每位作者可能有单独的文章标题列表

在multimap中,同一个键所关联的元素必然相邻存放

有三种策略:

1. 使用find和count操作

首先,调用count确定某作者所写的书籍数目,然后调用find获得指向第一个该键所关联的元素的迭代器。for循环迭代的次数依赖于count返回的值。

2. 另一个更优雅简洁的方法是使用两个未曾见过的关联容器的操作:lower_boundupper_bound

lower_bound:返回的迭代器指向该键关联的第一个实例

upper_bound:返回的迭代器指向最后一个实例的下一个位置

// beg and end denote range of elements for this ahuthortypedef 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 authorwhile (beg != end){cout << beg->second << endl; // print each title++beg;}
3. 更直接的方法是:调用equal_range函数来取代调用upper_bound和lower_bound函数。

equal_range函数返回存储一对迭代器的pair对象。如果该值存在,则pair对象的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一位置。如果找不着匹配的元素,则pair对象中两个迭代器都将指向此键应该插入的位置。

// pos holds iterators that denote range of elements for this keypair<authors_it, authors_it> pos = authors.equal_range(search_item);// loop through the number of entries there are for this authorwhile (pos.first != pos.second){cout << pos.first->second << endl; // print each title++pos.first;}

最后给出的"容器综合应用:文本查询程序"可以好好读读,自己尝试写写。

容器一直是我很薄弱的地方,在工作中很少能想到用关联容器来存储数据,即使有些数据的关系很符合关联容器的模式。读完这章发现关联容器也没有那么麻烦那么难,在以后的工作中可以尝试多多使用。


第十章 关联容器(完)

0 0
原创粉丝点击