三、【C++ STL】容器之关联式容器

1、关联式容器

  关联容器在存储时是以关键字key为下标进行存储的,标准的STL关联容器分为set和map两大类,以后的衍生版本有multiset和multimap,它们的区别是在存储时是否允许出现关键字key相同的状况。这些容器的底层机制均以RB-tree(红黑树)完成。ios

  此外,SGI STL还提供了一个不在标准规格之列的关联式容器:hash table,以及基于hash table而完成的hash_set和hash_map。但在C++11中,由于标准化的推动,unordered_map原来属于boost分支和std::tr1中,而hash_map属于非标准容器。尽可能使用unordered_,代替hash_,两者在底层上实现机理是同样的。数据结构

一、对组pair类型提供的操做

对组pair包含两个数据值。具体的使用方法以下:函数

 

1     pair<T1, T2> p1;

 

建立一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化。性能

 

 

1     pair<T1, T2> p1(v1, v2);

 

建立一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。学习

 

 

1     make_pair(v1, v2);

 

以v1和v2值建立一个新的pair对象,其元素的类型分别是v1和v2的类型。spa

 

 

1   p1 < p2;

 

两个pair对象之间的小于运算,其定义遵循字典次序:若是p1.first<p2.first或者!(p2.first<p1.first)&&p1.second<p2.second,返回true。.net

 

 

1   p1 == p2;

 

若是两个pair对象的first成员和second成员依次相等,则这两个对象相等,该运算使用其元素的==操做符。设计

 

 

1   p.first、p.second;

 

返回p中名为first、second的公有数据成员。code

 

二、pair的建立和初始化

  在建立pair对象时,必须提供两个类型名,pair对象的两个数据成员各自对应一个,这两个类型名能够不一样。若是在建立pair对象时不提供显示初始化,则调用默认构造函数对其成员进行初始化;也能够在建立对象时使用( )直接显示初始化式:
对象

1     pair<类型1, 类型2> 对象名;

 

若是使用多个相同的pair对象,也可使用typedef简化其声明:

1   typedef  pair <string, string>  Author;
2   Author 对象名(初始值1,初始值2);

 

对于pair类能够直接访问其数据成员,其成员都是公有的,分别命名为first成员和second成员,使用点操做符便可访问。

三、set和map

  通常来讲,关联式容器的内部结构是一个平衡二叉树,以便得到良好的搜寻效率,平衡二叉树有不少种类型,包括AVL-tree,RB-tree等,最被普遍使用的是RB-tree。

  (1)   搜索二叉树,由于它的查找平均性能是O(lgN),所以查询中多用这种结构,但若是创建搜索二叉树的时候数据不够随机,可能会致使这棵二叉树出现“左重右轻“之类的失衡状况,这个时候平衡二叉树便体现出它的做用了。

  (2)   所谓的树形平衡与否,并无一个绝对的测量标准,大体意义是没有任何一个节点过深。AVL树中定义是任何节点的左右子树高度相差最多为1,在插入新的元素的时候,可能会致使这棵AVL树失去平衡,这个时候就须要用到”单旋转”和“双旋转”两种操做来调节AVL树使之从新平衡。

  (3)   RB-tree是另外一种二叉平衡树,它对“平衡”的定义更弱,它的规则以下:

  A. 每一个节点不是红色就是黑色

  B. 根节点为黑色

  C. 若是节点为红色,那么它的子节点必须为黑色

  D. 任一节点至NULL的任何路径中,所含的黑色节点数必须相同

  因此对于RB-tree的插入和删除是一个很复杂的过程,其中,插入有3中状况,删除有4中状况,可是它能很好地保证查询的效率,一般来讲,比其余的平衡二叉树提升25%。

  在RB-tree中,有两个函数很重要,一个是pair<iterator,bool>insert_unique(const Value_type &x),这个是将x插入到红黑树中,而且保持节点的独一无二(一般来讲,若是使用insert函数在map插入新的元素,若是是重复元素,则不会真正插入,而是直接返回),返回值是一个pair类型,bool标志插入是否成功,iterator根据插入是否成功则指向新插入的节点或者NULL,另一个是pair<iterator,bool> insert_equal(constValue_type &x),这个函数再插入节点时容许节点关键字key重复,这即是multiset和multimap实现的关键了,这也是它们和set及map最大的区别了。

四、hash_set和hash_map

  二叉搜索树具备对数平均时间的表现,但这样的表构建在一个假设之:输入数据足够随机。除此以外,还有另一种数据结构,它在插入、删除、搜寻等操做上也具备常数平均时间,并且这种表现是以统计为基础,不须要依赖元素的随机性,它就是hash table。

  哈希表在处理冲突时有线性探测,二次探测以及开链等方式,SGI则是采用开链的方式,即将冲突的元素构成一个链表,在SGI提供的hashtable中表格内的元素为桶子(bucket),它是用vector来承载元素。

  虽然在开链法中并不要求表格大小必须为质数,可是SGI STL仍然以质数来设计表格,它是将预先选取的28个质数保存在表中,当用户要求分配多少个桶时,则返回不小于且最接近的一个质数做为表格大小。

       Hash_set和hash_map一样只须要调用hashtable中的函数便可。因为如今常用unordered_系列代替了hash_,因此对于hash_的具体用法就不赘述了。

2、set

一、set/multiset

  (1)全部元素都会根据元素的键值自动排列,set的键值就是实值,而且set不容许两个元素相同的键值。

  (2)不能经过set的迭代器改变set的元素值,由于set的元素值就是键值,所以这关系到排列规则,若是咱们擅自修改元素值,会破坏set内部的排列规则。也正由于这样,STL的set的迭代器是const_iterator。

  (3)STL集合的底层结构是红黑树。所以掌握了红黑树的基本操做,那么学习集合set将会很容易,几乎set的全部操做都是转调用红黑树的操做而已。

  (4)set内的相同数值的元素只能出现一次,multiset内可包含多个数值相同的元素。

【示例】

 1 #include <iostream>
 2 #include <set>//用set和multiset前,必须包含头文件<set>
 3 
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     //type of the collection
 9     typedef set<int> IntSet;
10 
11     IntSet coll;//set container for int values
12     //不可以用push_back()由于是自动排序
13     coll.insert(1);
14     coll.insert(6);
15     coll.insert(2);
16 
17     IntSet::const_iterator pos;
18     for(pos = coll.begin(); pos != coll.end(); pos++)
19         cout << *pos << "  ";
20     cout << endl;
21 
22     return 0;
23 }

二、map/multimap

  (1)map的元素是成对的键值/实值,内部的元素依据其值自动排序;

  (2)map内的相同数值的元素只能出现一次,multimap内可包含多个数值相同的元素。

  (3)STL集合的底层结构是红黑树。所以掌握了红黑树的基本操做,那么学习集合set将会很容易,几乎set的全部操做都是转调用红黑树的操做而已。

【示例】

 1 #include <iostream>
 2 //用map/multimap前,必须包含头文件<map>
 3 #include <map>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 int main()
 9 {
10     //type of the collection
11     typedef multimap<int, string> intStringMMap;
12 
13     intStringMMap coll;//container for int/string
14     //make_pair()便捷函数,返回一个pair对象:pir(first, second)
15     coll.insert(make_pair(6, "strings"));
16     coll.insert(make_pair(1, "is"));
17     coll.insert(make_pair(3, "multimap"));
18 
19     intStringMMap::iterator pos;
20     for(pos = coll.begin(); pos != coll.end(); pos++)
21     {
22         cout << pos->first << " " << pos->second << endl;;
23     }
24     cout << endl;
25 
26     return 0;
27 }
相关文章
相关标签/搜索