今天看到一个问题的解法用到了数学中set的概念,想到c++中也有set就翻书看了一下,不过发现说的挺简单的,主要还是基于map实现的。而map得实现我也一直没有认真了解过,今天就借着这个机会学习一下。
map,中文名映射,也叫关联数组,或者字典(dictionary)。保存的是值得对偶。
定义是这样的:
template<class K, class V> class Assoc {
public:
V& operator[] (const K&);
};
c++中几种关联容器的关系是这样的:map是关联数组,multimap是允许元素中出现重复关键码的关联数组,set和multiset是退化的关联数组,其中没有与关键码相关联的值。事实上set和multiset可以认为是map和multimap的adapter。
map
map提供了双向迭代器。注意的是map的key需要提供<操作,即Map的元素是有序的,迭代Map也是有序的。对于没有顺序的元素和不必保持有序的情况,可以考虑使用hash_map(这个后面也要学习)。
map的确些类型由实现决定,最有可能被实现为某种形式的树。由此可以推断map涉及下标的操作复杂度为log(n)。例如插入,查找(访问)等。
下标运算符将关键码作为下标去执行查找,并返回对应的值。如果不存在这个关键码,它就将一个具有该关键码和mapped_type类型默认值插入到这个Map。如果你不希望因为访问而修改Map,应该使用find()。
另两类和find()相似的操作是:lower_bound(), upper_bound(),和range_equal()。这些操作用在multimap中。
insert()和erase()可以插入和删除。insert()的返回值很是奇特,是pair<iterator, bool>。
另外insert()还有其它版本,一种是insert(pos, val)。这个实在是太难使用了,但在特定的环境下可以提高效率。
multimap
允许重复的关键码。这个对象可以解决挺多问题,很多时候我喜欢用map<key, vector<value> >来表示某些数据结构,其实使用multimap就可以了。
multimap是不支持下标操作的,使用lower_bound(), upper_bound(), 和range_equal()进行访问。
set
set的概念和数学上的结合很像,但是有一些特性却是要注意的。比如set因为是利用map实现的,所以set里的元素也是排序的。这意味着set的插入,删除,查找都是复杂度为log(n)的。但是仔细想想,除非牺牲空间,否则也只有进行排序才可以容易知道一个元素是否已经存在。但是set是依赖于<的比较操作,而不是==,对于否些仅仅能区分是否相等的对象放入set中增加了难度。
multiset
和set类似,但是允许重复的关键码。
bitset
这个对象平时很少见别人使用。大概看了一下接口定义,感觉挺方便的,不用自己记忆和维护那些抽象易错的位操作函数了。