关联容器根据键来存储数据元素。键由一项或多项属性组成,可以唯一的标识数据元素。
作为一种ADT , 关联容器与以前章节中的向量,表等顺序容器很相似。她是另外一种存储结构,提供了不同的方法来访问和修改元素。主要的不同之处在于,容器类使用键获取元素,而不是通过下标或者线性搜索算法。在使用键时,不用考虑元素在容器中物理存储方式,也不必考虑操作函数如何在建和数据元素间建立联系。
STL提供了两种关联容器:集合(set) 和 映射(map) 。中两种容器的元素结构不同。在集合中,数据元素的值就是键,但在映射中,存储的是 “键 --值”对,键和值是彼此分离的部分。
应用程序可能需要用集合来存储更复杂的数据项,这些数据项由记录描述。每项数据都由两个或更多个字符按组成,其中包括键字段。键字段唯一的标识数据项。其他字段提供附加信息。在类中,可以把各个字段定义成私有的数据成员,因此,能够用类来描述记录 。
为了支持集合操作,类中要重载 == 运算符 和 < 运算符。
set < T> 的查找函数用T对象作为参数,并利用重载的比较运算符,根据参数的键来访问容器中的元素。该函数将从集合中返回匹配参数键的对象,然后程序就可以访问或更新非键字段。
键—值 数据:映射按照键—值 对的方式来存储数据。在键值对中,键位第一个部分,值是第二个部分。这两个部分可以是不同的类型 。
映射容器有两个模板参数,分别是键的类型和值的类型。map<T , S>
映射的查找函数使用键作为参数,返回一个指向pair对象的迭代器,该数据对的键分量与参数相匹配。然后程序就可以访问或更新pair对象中的值分量。
映射容器重载了下标运算符[],使映射容器具有了这种访问方式。该运算符把键作为参数,返回pair对象中值分量的引用。如同数组下标一样,该运算符可以用于赋值语句的任何一端。
因为有了下标运算符,所以也称映射为关联数组。
STL定义的集合和映射容器不允许重复的键,STL提供了多重集合多重映射容器。
11.1.3 实现关联容器
由于内部的存储结构是查找树,所以,集合和映射可以用迭代器按键递增的顺序遍历元素。凭借这种实现方式,STL实现了有序关联容器。容器的迭代器在二叉搜索树内按中序遍历,因此可以按元素的大小顺序访问他们。于是,这些结构都是有序关联容器。
11.2 集合
集合的迭代器定义了遍历集合元素时的访问顺序。默认情况下,STL set类迭代器按照键的递增顺序遍历元素。因此,begin指向集合中最小的元素,end指向集合中最大的元素的后面。
set类函数集:
set::set
explicit set(const Pred& comp = Pred(), const A& al = A());
set(const set& x);
set(const value_type *first, const value_type *last,
const Pred& comp = Pred(), const A& al = A());
set::empty
bool empty() const;
The member function returns true for an empty controlled sequence.
set::count
size_type count(const Key& key) const;
The member function returns the number of elements x
in the range [
lower_bound
(key),
upper_bound
(key)).
set::find
const_iterator find(const Key& key) const;
The member function returns an iterator that designates the earliest element in the controlled sequence whose sort key equals key
. If no such element exists, the iterator equals end
()
.
set::insert
pair<iterator, bool> insert(const value_type& x);
iterator insert(iterator it, const value_type& x);
void insert(const value_type *first, const value_type *last);
The first member function determines whether an element y
exists in the sequence whose key matches that of x
. (The keys match if !
key_comp
()(x, y) && !key_comp()(y, x)
.) If not, it creates such an element y
and initializes it with x
. The function then determines the iterator it
that designates y
. If an insertion occurred, the function returns pair
(it, true)
. Otherwise, it returns pair(it, false)
.
The second member function returns insert(x)
, using it
as a starting place within the controlled sequence to search for the insertion point. (Insertion can occur in amortized constant time, instead of logarithmic time, if the insertion point immediately follows it
.) The third member function inserts the sequence of element values in the range [first, last)
.
In this implementation, if a translator does not support member template functions, the template:
template<class InIt>
void insert(InIt first, InIt last);
is replaced by:
void insert(const value_type *first, const value_type *last);
set::erase
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
size_type erase(const Key& key);
The first member function removes the element of the controlled sequence pointed to by it
. The second member function removes the elements in the range [first, last)
. Both return an iterator that designates the first element remaining beyond any elements removed, or end
()
if no such element exists.
The third member removes the elements with sort keys in the range [
lower_bound
(key),
upper_bound
(key)).
It returns the number of elements it removes.
set::begin
const_iterator begin() const;
The member function returns a bidirectional iterator that points at the first element of the sequence (or just beyond the end of an empty sequence).
set::end
const_iterator end() const;
The member function returns a bidirectional iterator that points just beyond the end of the sequence.
11.2.5 集合运算
有些版本的集合和多重集合容器只实现 了常量迭代器。那么*ITER = Value 是不允许的。同样,假设使用这个迭代器来调用它自己的成员函数f() ,如下(*ITER).f() ; 其中,函数f()必须被声明为常量型的成员函数。 returntype f() const ;
11.3 映射
映射是一种关联容器,其内部存储的是 键—值 pair对象。一个 pair对象由两个分量组成。每个分量都可以有独自的数据类型。作为一种存储结构,映射和集合的接口十分类似。实际上,可以把映射想象成是一个“pair对象的集合”。
映射有两个模板参数,这两个模板类型分别对应于pair对象的键分量和值分量。template<typename Key , typename T> ,通常情况下,键的类型是string ,值的类型可以是任意对象类型。
映射容器中的元素是pair<Key , T>类型对象。为了简化表示,map类使用typedef语句使数据类型pair<Key , T>等价于标识符Value_type ;
typedef pair<Key , T> value_type ;
在使用标识符value_type 时,要加上map作用域运算符,因为正是在map类中定义的value_type 。
//声明一个pair<string , int> 对象的数组,这个pair对应于课程名称和选修该科的人数
map<string , int >::value_type arr[] = {map<string , int >::value_type (“econ”,85),map<string , int >::value_type (“cs”,100),map<string , int >::value_type (“engl”,63)};
在程序中可以把自己定义的数据类型map<string , int >::value_type 再次定义为类型entry ,
typedef map<string , int >::value_type entry ;
则定义可些为::
entry arr[] = {entry(“econ”,85),entry(“cs”,100),entry(“engl”,63)} ;
int arrSize = sizeof(arr) / sizeof(entry) ;
map<string , int > mapObj(arr, arr + arrSize) ;
映射的迭代器: map<Key , T>::iterator iter ;
(*iterator).first ; (*iterator).second .
11.3.3映射的下标运算符
映射按照数据对的形式存储元素,每个元素都有其独特的键。于是,我们可以把映射结构看成是关联数组,元素的键位数组的下标。为了实现这个特性,map类重载了下标运算符,重载函数的参数为键,返回值是pair对象中值分量的指针。
T& operator[] (const Key& key) ;
由于返回值是引用,所以可以在赋值语句的任何一端用映射的下标表达式。
当映射中没有对应指定键的元素时,下标运算符会像insert()函数那样添加一个新元素。该元素是pair对象,由键和类型T的默认值组成。运算符返回的是新元素值分量的引用。
例如,下面的语句,映射中没有键为“MATH 51”的数据项,下面的语句中,下标运算符建立了 一个“键--值”pair对象(MATH 51 , 0 ),把她加入到映射中,并返回值分量的引用。赋值运算符右边的45替代了默认值 0 ;
mapObj[“MATH 51”] = 45 ;
另一个例子:程序在赋值语句的右边用了下标运算符,而且映射中没有包含指定键的元素,运算符将建立一个新的映射数据项,并返回他的默认值。
coursecount = mapObj[“BUS 31”] ; // 返回0 ;
11.4 多重集(multiset)
标准模板库定义了多重集合多映射容器,他们是set类和map类的扩展,允许重复的数据项。
count()函数需要一个类型T的参数item , 返回所有匹配item的元素个数。在多重集中,count()的返回值可能会大于1。
insert()汉化苏总是能把一个新元素添加到多重集中,因为多重集是允许重复键存在的。该函数的返回值不再是pair对,而是指向新元素的单个迭代器。
与集合一样,erase()函数也有多个版本,他们的参数有的是数值,也有的是迭代器。当erase函数用数值作为参数时,她将删除多重集中所有匹配的元素,并返回被删除元素的个数。如果erase()函数的参数是迭代器或者是迭代器区间,那么他将只删除指定位置上的元素。
函数find()返回指向第一个目标元素的迭代器。
为了能够访问到所有匹配item的元素,multiset类提供了一个函数equal_range(),她把item作为参数,返回一对迭代器来指定匹配键item的元素范围。迭代器的first分量指向第一个匹配item的 元素,second指向最后一个匹配元素的下一个位置。
pair<multiset<int>::iterator , multiset<int>::iterator> p ;
p = equal_range(item) ;
multiset::equal_range
pair<const_iterator, const_iterator>
equal_range(const Key& key) const;
The member function returns a pair of iterators x
such that x.first ==
lower_bound
(key)
and x.second ==
upper_bound
(key)
.
11.5 实现集合和映射