0
点赞
收藏
分享

微信扫一扫

C++:关联容器(set,multiset,map,multimap)


关联容器(associative container)是对容器概念的一种改进.

关联容器将值与键关联在一起,并使用键来查找值。

例:值可以是表示员工信息(如姓名,电话,地址,性别,健康计划等)的结构体,而键可以是唯一的员工编号。为获取员工信息,程序使用键查找员工结构。

关联容器的优点:

提供了对元素的快速访问,也允许插入新元素,但不能指定元素的插入位置(原因是关联容器通常用于确定数据放置位置的算法,以便能快速检索信息)

关联容器通常是使用某种树实现的。树是一种数据结构,其根节点链接到一个或两个节点,而这些节点又链接到一个或两个节点,从而形成分支结构。

像链表一样,节点使得添加或删除数据比较简单,但对于链表,树的查找速度更快。

STL提供了4种关联容器:

set :

multiset : 这两种头文件都为set

map :

multimap :这两种头文件都为map


set:是其中最简单的关联容器,其值类型与键相同,键是唯一的,这意味着集合中不会有多个相同的键。对于set来说,其值就是键

multiset:类似于set,只是可能有多个值的键相同。

map:其值与键的类型不同,键是唯一的,每个键只对应一个值。

multimap:类似于map,只是一个键可以与多个值关联。


1)set示例:

set<string> A; //可以带第二个参数(可 选),默认情况使用模板less<>

set<string, less<string> > A; // older implementation

#include <iostream>
#include <set>
#include <string>

int main()
{
using namespace std;
const int N = 6;
string s1[N] = {"buffoon", "thinkers", "for", "heavy", "can", "for"};//注意这里有两个相同的for
set<string> A(s1, s1 + N);//set不仅去重,还按升序排序
ostream_iterator<string, char> out(cout, " ");
copy(A.begin(), A.end(), out);//buffoon can for heavy thinkers
cout << endl;
return 0;
}


数学还为set定义了一些标准操作,如

并集:包含两个集合合并后的内容。如果两个集合包含相同的值,则这个值在并集中只出现一次,因为set的键是唯一的。



    set_union(A.begin(), A.end(), B.begin(), B.end(), C.begin());//放入C集合中,这种做法是错误的


            1)首先,关联集合将键看作常量,所以C.begin()返回的迭代器是常量迭代器,不能用作输出迭代器。

            2)其次,与copy()相似,set_union()将覆盖容器中已有的数据,并要求容器有足够的空间来容纳新信息。C是空的,不能满足这种要求。

            但模板insert_iterator可以解决这两个问题,它可以将复制转换为插入。另外,它可以模拟输出迭代器,可以用它将信息写入容器。

            所以这里可以创建一个匿名insert_iterator,将信息复制给C,如:

    set_union(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> >(C, C.begin()));

交集:包含两个集合都有的元素。

            set_intersection(),用法与set_union类似

差集:两个集合的差是第一个集合减去两个集合都有的元素。

            set_difference(),用法与set_union类似

STL提供了支持这些操作的算法。它们是通用函数,并非只用于set对象。

所以set对象都自动满足这些算法的先决条件,即容器是经过排序的。


两个有用的set方法:

lower_bound():将键作为参数返回一个迭代器,该迭代器指向集合中第一个不小于键参数的成员。

upper_bound():将键作为参数返回一个迭代器,该迭代器指向集合中第一个大于键参数的成员。

作用:可以获取一个包含合集的区间。


set中因为会自动排序,所以只需指定插入的信息,不需指定插入位置。

关于上述说明的实例应用:

#include <iostream>
#include <set> // set
#include <string> // string
#include <algorithm> //set_union
#include <iterator>
int main()
{
using namespace std;
const int N = 6;
string s1[N] = {"buffoon", "thinkers", "for", "heavy", "can", "for"};//注意这里有两个相同的for
string s2[N] = {"metal", "any", "food", "elegant", "deliver", "for"};

set<string> A(s1, s1 + N);//set不仅去重,还按升序排序
set<string> B(s2, s2 + N);
ostream_iterator<string, char> out(cout, " ");

cout << "Set A:\n";
copy(A.begin(), A.end(), out);//buffoon can for heavy thinkers
cout << endl;

cout << "Set B:\n";
copy(B.begin(), B.end(), out);//any deliver elegant food for metal
cout << endl;

cout << "Union of A and B:\n";
set_union(A.begin(), A.end(), B.begin(), B.end(), out);
//any buffoon can deliver elegant food for heavy metal thinkers
cout << endl;

cout << "Intersection of A and B:\n";
set_intersection(A.begin(), A.end(), B.begin(), B.end(), out); //for
cout << endl;

cout << "Difference of A and B:\n";
set_difference(A.begin(), A.end(), B.begin(), B.end(), out);//buffoon can heavy thinkers
cout << endl;

set<string> C;
cout << "Set C:\n";
set_union(A.begin(), A.end(), B.begin(), B.end(),
insert_iterator<set<string> >(C, C.begin()));//将A与B的并集放入C集合中
copy(C.begin(), C.end(), out);
//any buffoon can deliver elegant food for heavy metal thinkers
cout << endl;

string s3("grungy");
C.insert(s3);
cout << "Set C After insert s3:\n";
copy(C.begin(), C.end(), out);
//any buffoon can deliver elegant food for grungy heavy metal thinkers
cout << endl;

cout << "Showing a range:\n";
copy(C.lower_bound("ghost"), C.upper_bound("spook"), out);
//grungy heavy metal
cout << endl;
return 0;
}


multimap示例:

multimap<int, string> codes; //#1

第三个参数是可选的,指出用于对键进行排序的比较函数或对象。在默认情况下,使用模板less(),该函数将键类型用作模板参数类型。

实际的值将键类型与数据类型结合为一对,pair<class T, class U>,

如果keytype是键类型,datatype是存储的数据类型,则值类型为pair<const keytype, datatype>,  如#1处,codes的对象的值的类型为pair<const int, string>;

假设用区号作为键来存储城市名,则

pair<const  int, string> item(213, "Los Angeles"); //声明一个
codes.insert(item); //插入

也可以创建匿名对象来写:

codes.insert(pair<cosnt int, string> (213, "Los Angeles"));

因为数据项是按键排序的,所以不用指出插入位置。

访问里面的内容:

cout << item.first << " " << item.second << endl;

first表示键值,second表示数据信息。

equal_range()用键作为参数,且返回两个迭代器,它们返回的区间与该键匹配。为返回这两个值,该方法将封装在一个pair对象中,这里pair的两个模板参数都是迭代器

 如打印codes对象中区号为718的所有城市:

pair<multimap<KeyType, string>::iterator, multimap<KeyType, string>::iterator> range = codes.equal_range(718);
std::multimap<KeyType, string>::iterator it;
for (it = range.first; it != range.second; ++it)
cout << (*it).second << endl;

如用C++11的自动推断功能,则:

auto range =  = codes.equal_range(718);
for (auto it = range.first; it != range.second; ++it)
cout << (*it).second << endl;

也可使用typedef

#include <iostream>
#include <string>
#include <map>
#include <algorithm>

typedef int KeyType;
typedef std::pair<const KeyType, std::string> Pair;
typedef std::multimap<KeyType, std::string> MapCode;

int main()
{
using namespace std;
MapCode codes;

codes.insert(Pair(415, "San Francisco"));
codes.insert(Pair(510, "Oakland"));
codes.insert(Pair(718, "Brooklyn"));
codes.insert(Pair(718, "Staten Island"));
codes.insert(Pair(415, "San Rafael"));
codes.insert(Pair(510, "Berkeley"));
codes.insert(Pair(510, "Carry"));

// count指出有几个键相同的值
cout << "key 415: " << codes.count(415) << endl; // 2
cout << "key 718: " << codes.count(718) << endl; // 2
cout << "key 510: " << codes.count(510) << endl; // 3

cout << "All codes:\n";
MapCode::iterator it;
for (it = codes.begin(); it != codes.end(); ++it)
cout << (*it).first << " " << (*it).second << endl;
// All codes:
// 415 San Francisco
// 415 San Rafael
// 510 Oakland 不知道为什么它会在这里???
// 510 Berkeley
// 510 Carry
// 718 Brooklyn
// 718 Staten Island

//找出所有键值相同的
pair<MapCode::iterator, MapCode::iterator> range = codes.equal_range(718);
cout << "key 718:\n";
for (it = range.first; it != range.second; ++it)
cout << (*it).second << endl;
// key 718:
// Brooklyn
// Staten Island
return 0;
}


无序关联容器(C++11)

无序关联容器也是对容器概念的另一种改进。与关联容器一样。

底层区别:关联容器是树结构,无序关联容器是基于数据结构哈希表的,其目的在于提高添加与删除元素的速度以及提高查找算法的效率。

有4种无序关联窗口:

1)unordered_set

2)unordered_multiset

3)unordered_map

4)unordered_multimap







举报

相关推荐

0 条评论