Part10 泛型程序设计与C++标准模板库 10.5关联容器
1关联容器分类和基本功能
关联容器的特点和接口
关联容器的特点
每个关联容器都有一个键(key)
可以根据键高效地查找元素
接口
插入:insert
删除:erase
查找:find
定界:lowerbound、upperbound、equal_range
计数:count
四种关联容器
单重关联容器(set和map)
键值是唯一的,一个键值只能对应一个元素
多重关联容器(multiset和multimap)
键值是不唯一的,一个键值可以对应多个元素
简单关联容器(set和multiset)
容器只有一个类型参数,如set、multiset,表示键类型
容器的元素就是键本身
二元关联容器(map和multimap)
容器有两个类型参数,如map<K,V>、multimap<K,V>,分别表示键和附加数据的类型
容器的元素类型是pair<K,V>,即由键类型和元素类型复合而成的二元组
无序关联容器
C++11 新标准中定义了4个无序关联容器
unorderedset、unorderedmap、unorderedmultiset、unorderedmultimap
不是使用比较运算符来组织元素的,而是通过一个哈希函数和键类型的==运算符。
提供了与有序容器相同的操作
可以直接定义关键字是内置类型的无序容器。
不能直接定义关键字类型为自定义类的无序容器,如果需要,必须提供我们自己的hash模板。
2集合(set)
集合用来存储一组无重复的元素。
由于集合的元素本身是有序的,可以高效地查找指定元素,也可以方便地得到指定大小范围的元素在容器中所处的区间。
//例10-9 输入一串实数,将重复的去掉,取最大和最小者的中值,分别输出小于等于此中值和大于等于此中值的实数 #include<iostream> #include<iterator> #include<utility> #include<set> using namespace std; int main(){ set<double> s; while(true){ double v; cin >> v; if(v == 0) break; //输入0表示结束 pair<set<double>::iterator, bool> r = s.insert(v); if(!r.second) //如果v已存在,输出提示信息 cout << v << " is duplicated" << endl; } set<double>::iterator iter1 = s.begin(); set<double>::iterator iter2 = s.end(); double medium = (*iter1 + *(--iter2)) / 2; //得到最小和最大元素的中值 cout << "<= medium: "; copy(s.begin(), s.upper_bound(medium), ostream_iterator<double>(cout, " ")); cout << endl; cout << ">= medium: "; copy(s.lower_bound(medium), s.end(), ostream_iterator<double>(cout, " ")); cout << endl; return 0; }
3映射(map)
映射与集合同属于单重关联容器,它们的主要区别在于,集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组。
在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定它的存在性外,还可以得到相应的附加数据。
//例10-10 有五门课程,每门都有相应学分,从中选择三门,输出学分总和 #include<iostream> #include<map> #include<string> #include<utility> using namespace std; int main(){ map<string, int> courses; courses.insert(make_pair("CSAPP",3)); courses.insert(make_pair("C++",2)); courses.insert(make_pair("CSARCH", 4)); courses.insert(make_pair("COMPILER", 4)); courses.insert(make_pair("OS", 5)); int n = 3; int sum = 0; while(n>0){ string name; cin >> name; map<string, int>::iterator iter = courses.find(name); if(iter == courses.end()){ cout << name << " is not available" << endl; }else{ sum += iter->second; courses.erase(iter); n--; } } cout << "Total credit: " << sum << endl; return 0; }
//例10-11 统计一句话中每个字母出现的次数 #include<iostream> #include<map> #include<cctype> using namespace std; int main(){ map<char, int> s; char c; do{ cin >> c; if(isalpha(c)){ c = tolower(c); s[c]++; } }while(c != '.'); //碰到“.”则结束输入 for(map<char, int>::iterator iter = s.begin(); iter != s.end(); ++iter) cout << iter->first << " " << iter->second << " "; cout << endl; return 0; }
4多重集合(multiset)与多重映射(multimap)
多重集合是允许有重复元素的集合,多重映射是允许一个键对应多个附加数据的映射。
多重集合与集合、多重映射与映射的用法差不多,只在几个成员函数上有细微差异,其差异主要表现在去除了键必须唯一的限制。
//例10-12 上课时间查询 #include<iostream> #include<map> #include<utility> #include<string> using namespace std; int main(){ multimap<string, string> courses; typedef multimap<string, string>::iterator CourseIter; courses.insert(make_pair("C++","2-6")); courses.insert(make_pair("COMPILER", "3-1")); courses.insert(make_pair("COMPILER", "5-2")); courses.insert(make_pair("OS","1-2")); courses.insert(make_pair("OS","4-1")); courses.insert(make_pair("OS","5-5")); string name; int count; do{ cin >> name; count = courses.count(name); if(count == 0) cout << "Cannot find this course!" << endl; }while(cout == 0); cout << count << " lesson(s) per week: "; pair<CourseIter, CourseIter> range = courses.equal_range(name); for(CourseIter iter = range.first; iter != range.second; ++iter) cout << iter->second << " "; cout << endl; return 0; }