C++ primer plus 第16章string 类和标准模板库, 关联容器

C++ primer plus 第16章string 类和标准模板库, 关联容器

C++ primer plus 第16章string 类和标准模板库, 关联容器


16.4.4关联容器

关联容器(associative container)是对容器概念的另一个改进。关联容器将值与键关联在一起,并使用键来查找值。例如,值可以是表示雇员信息(如姓名、地址、办公室号码、家庭电话和工作电话、健康计划等)的结构,而键可以是唯一的员工编号。为获取雇员信息,程序将使用键查找雇员结构。前面说过,对于容器X,表达式X::value_type 通常指出了存储在容器中的值类型。对于关联容器来说,表达式X::key type 指出了键的类型。
关联容器的优点在于,它提供了对元素的快速访问。与序列相似,关联容器也允许插入新元素,但不能指定元案的插入位置。原因是关联容器通常有用于确定数据放置位置的算法,以便能够快速检索信息。关联容器通常是使用某种树实现的。树是一种数据结构,其根节点链接到一个或两个节点,而这些节点又链接到一个或两个节点,从而形成分支结构。像链表一样,节点使得添加或删除数据项比较简单:但相对于链表,树的查找速度更快。
STL提供了4种关联容器:set、multiset、map和multimap。前两种是在头文件 set(以前分别为 set.h和 multiset.h)中定义的,而后两种是在头文件 map(以前分别为 map.h和 multimap.h)中定义的。
最简单的关联容器是 set,其值类型与键相同,键是唯一的,这意味着集合中不会有多个相同的键。确实,对于set来说,值就是键。multiset类似于set,只是可能有多个值的键相同。例如,如果键和值的类型为 int,则 multiset对象包含的内容可以是1、2、2、2、3、5、7、7。
在 map 中,值与键的类型不同,键是唯一的,每个键只对应一个值。multimap与 map 相似,只是一个键可以与多个值相关联。
有关这些类型的信息很多,无法在本章全部列出(但附录G列出了方法),这里只介绍一个使用set的简单例子和一个使用 multimap 的简单例子。

1.set 示例

STLset模拟了多个概念,它是关联集合,可反转,可排序,且键是唯一的,所以不能存储多个相同的值。与vector和list相似,set也使用模板参数来指定要存储的值类型:

set<string>A;//aset of string objects

第二个模板参数是可选的,可用于指示用来对键进行排序的比较函数或对象。默认情况下,将使用模板 less<>(稍后将讨论)。老式C++实现可能没有提供默认值,因此必须显式指定模板参数:

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

请看下面的代码:

const int N=6;
string sl[N]=("buffoon","thinkers", "for", "heavy","can", "for");set<string>A(sl,s1+N);//initialize set A using a range from array
ostream iterator<string,char>out(cout,"");
copy(A.begin(),a.end(),out);

与其他容器相似,set也有一个将迭代器区间作为参数的构造函数(参见表16.6)。这提供了一种将集合初始化为数组内容的简单方法。请记住,区间的最后一个元紧是超尾,s1+N指向数组s1尾部后面的一个位置。上述代码片段的输出表明,键是唯一的(字符串“for”在数组中出现了2次,但在集合中只出现1次),且集合被排序:
buffoon can for heavy thinkers
数学为集合定义了一些标准操作,例如,并集包含两个集合合并后的内容。如果两个集合包含相同的值,则这个值将在并集中只出现一次,这是因为键是唯一的。交集包含两个集合都有的元素。两个集合的差是第一个集合减去两个集合都有的元素。
STL提供了支持这些操作的算法。它们是通用函数,而不是方法,因此并非只能用于set对象。然而,所有 set对象都自动满足使用这些算法的先决条件,即容器是经过排序的。setunion()函数接受5个迭代器参数。前两个迭代器定义了第一个集合的区间,接下来的两个定义了第二个集合区间,最后一个迭代器是输出迭代器,指出将结果集合复制到什么位置。例如,要显示集合A和B的并集,可以这样做:

set_union(A.begin(),A.end(),B.begin(),B.end(),
ostream iterator<string,char>out(cout,""));

假设要将结果放到集合C中,而不是显示它,则最后一个参数应是一个指向C的迭代器。显而易见的选择是C.begin(),但它不管用,原因有两个。首先,关联集合将键看作常量,所以Cbegin()返回的迭代器是常量迭代器,不能用作输出迭代器。不直接使用C.begin()的第二个原因是,与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 diference()分别査找交集和获得两个集合的差,它们的接口与set union()相同。两个有用的set方法是lowerbound()和upperbound()。方法lower bound()将键作为参数并返回一个迭代器,该迭代器指向集合中第一个不小于键参数的成员。同样,方法upper_bound()将键作为参数,并返回一个迭代器,该迭代器指向集合中第一个大于键参数的成员。例如,如果有一个字符串集合,则可以用这些方法获得一个这样的区间,即包含集合中从“b”到“f”的所有字符串。
因为排序决定了插入的位置,所以这种类包含只指定要插入的信息,而不指定位置的插入方法。例如,如果A和B是字符串集合,则可以这样做:

string s(</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值