set
1.set的迭代器是constant iterators,也就是说,不能通过迭代器修改set元素值。
2.自动排序。不允许两个元素有相同值。
3.插入新的元素和删除元素,不会造成旧的迭代器失效。
4.底层是红黑树。它的功能基本上就是调用底层红黑树的接口。
set的模板参数是:
template <class Key, class Compare = less<Key>, class Alloc = alloc>
而rb_tree的模板参数是
template <class key_type, class value_type, class KeyOfValue, class key_compare, class Alloc>
rb_tree的key_type和value_type都取set的Key,而KeyOfValue则使用identity<value_type>
(即返回自身),key_compare则取自set的Compare。
5.set的insert操作,如果参数是数字,返回的就是一对pair,如果成功插入(原树中没有这个数字),first是插入位置的迭代器,second是true;否则,first是原树中这个数字所在位置的迭代器,second是false。
set使用红黑树的insert_unique操作而不是insert_equal操作。因为它不允许两个元素有相同值。
set有接受一个迭代器范围的构造函数,它实际上就是调用了insert_equal操作,把它们挨个插进红黑树里面。
6.底层红黑树返回的都不是constant iterator,所以为了上面的第1条,要经常做强制类型转换,转换成const iterator。同样,向红黑树中传递迭代器参数时,也要进行强制类型转换,因为红黑树的函数都只接受非const的iterator。
7.set有key_comp
和value_comp
两个函数,它们实际上返回的都是模板中提供的Compare类型。
8.set自己的find函数比stl算法的find函数高效。
map
1.map的迭代器比较特别,既不是constant的,也不是mutable的。map中的键是不能修改的,但值是可以修改的。
2.自动排序。不允许两个元素的键有相同值。
3.插入新的元素和删除元素,不会造成旧的迭代器失效。
4.底层是红黑树。它的功能基本上就是调用底层红黑树的接口。
map的模板参数是:
template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>
而rb_tree的模板参数是
template <class key_type, class value_type, class KeyOfValue, class key_compare, class Alloc>
rb_tree的key_type就是Key,而value_type是pair<const Key, T>
(注意这里的const),KeyOfValue是select1st<value_type>
,它取的是value_type的first。key_compare是Compare。
5.map的insert操作,如果参数是数字,返回的就是一对pair,如果成功插入(原树中没有这个数字),first是插入位置的迭代器,second是true;否则,first是原树中这个数字所在位置的迭代器,second是false。
map使用红黑树的insert_unique操作而不是insert_equal操作。因为它不允许两个元素有相同值。
map有接受一个迭代器范围的构造函数,它实际上就是调用了insert_equal操作,把它们挨个插进红黑树里面。
6.底层红黑树返回的都不是constant iterator,所以为了上面的第1条,要经常做强制类型转换,转换成const iterator。同样,向红黑树中传递迭代器参数时,也要进行强制类型转换,因为红黑树的函数都只接受非const的iterator。
7.map有key_comp
和value_comp
两个函数。key_comp
返回的就是模板中提供的Compare类型对象。而map自定义了一个仿函数类value_compare,它重载的()符号,实际上就是对first调用了Compare。value_comp
返回的是value_compare类型对象。
8.map自己的find函数比stl算法的find函数高效。
9.map重载了[]
符号:
T& operator[] (const key_type& k) {
return (*((insert(value_type(k, t()))).first)).second;
}
这里的T,实际上就是键值对中值的类型。
从内向外读,首先是insert(value_type(k, t()))
,插入的键值对value的键来自形参k,而值是T类型默认构造的。
然后insert操作返回的是pair<iterator, bool>
类型,所以用first取出迭代器:(insert(value_type(k, t()))).first
然后对迭代器解引用*((insert(value_type(k, t()))).first)
,得到的是value_type类型。
value_type类型也是pair类型(键值对),所以取出它的second,就是值。返回的是这个值。
注意这里operator[]
的返回值是引用类型,而对于insert操作,如果map中没有要插入的值,就插入并返回插入位置的迭代器,如果要插入的值已经存在了,就直接返回原来位置的迭代器。所以这个操作符既可以当左值使用,也可以当做右值使用。
map<string, int> simap;
simap[string("jjhou")] = 1; // 左值运用
...
int number = simap[string("jjhou")] // 右值运用
multiset
1.允许键值重复,所以它和set的唯一区别是使用insert_equal
而不是insert_unique
。
multimap
1.允许键值重复,所以它和map的区别之一是使用insert_equal
而不是insert_unique
。
2.不能使用[]
符号来做插入 。