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

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 last
next_auth = make_pair(first, last); 
此操作等价于:

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


P470:

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

// count number of times each word occurs in the input
map<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> object
cout << map_it->first; // prints the key for this element
cout << " " << map_it->second; // prints the value of the element
map_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 value
word_count["Anna"] = 1;
map迭代器返回 value_type类型的值——包含 const key_typemapped_type类型成员的pair对象;下标操作符则返回一个 mapped_type类型的值

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

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


P477:

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

// if Anna not already in word_count, inserts new elements with value 1
word_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 input
map<string, int> word_count; // empty map from string to int
string word;
while (cin >> word)
{
	// inserts element with key equal to word and value 1;
	// if word already in word_count, insert does nothing
	pair<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 element
map<string, int>::const_iterator map_it = word_count.begin();
// for each element in the map
while (map_it != word_count.end())
{
	// print the element key, value pairs
	cout << 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 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

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 ahuthor
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;
}
3. 更直接的方法是:调用 equal_range函数来取代调用upper_bound和lower_bound函数。

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

// 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;
}

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

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


第十章 关联容器(完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值