string
、vector
、list
、deque
等容器,而这些容器因为其底层是线性序列的数据结构,里面存储的是元素本身,所以我们将它们称之为序列式容器;template <class T1, class T2>
struct pair{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair()
:first(T1())
,second(T2())
{}
pair(const T1& a, const T2& b)
:first(a)
,second(b)
{}
};
template <class T1, class T2>
struct pair;
pair
对象中存在两个成员变量:pair<int, int> p(2, 5);
p.first:获取键值对中的第一个数据的值;
p.second:获取键值对中的第二个数据的值;
pair<数据类型1, 数据类型2> p;
:构造空的键值对;pair<数据类型1, 数据类型2> p(数据1, 数据2);
:构造含有关键码和数据值的键值对;pair<数据类型1, 数据类型2> p(同类型的键值对);
:用已有键值对构造一个键值对,这两个键值对数据类型要保持一致;pair& operator= (const pair& pr);
:将一个已有键值对的值赋给另一个已有键值对,这两个键值对数据类型要保持一致;void swap (pair& pr);
:交换两个键值对的关键码和数据值,这两个键值对数据类型要保持一致;make_pair
函数可以为空的键值对创建出一个键值对对象;template <class T1, class T2>
pair<T1,T2> make_pair(T1 x, T2 y);
pair<int, int> p;
p = make_pair(2, 4);
set
set
是按照一定次序存储键值对的容器;set
中,元素的 value 和 key 是相同的 (value == key,类型都为 T),因此每个 value 必须是唯一的,并且set
中的元素不能在容器中修改 (元素总是const
的),但是可以从容器中插入或删除它们;set
中的元素总是按照其内部比较对象 (所存储的数据类型的比较规则) 所指示的特定严格弱排序准则进行排序;set
容器通过 key 访问单个元素的速度通常比unordered_set
容器慢,但它们允许根据顺序对子集进行直接迭代;set
在底层是用二叉搜索树 (红黑树) 实现的;set
时需要包含头文件
;template < class T, //set存放的元素类型中元素
class Compare = less<T>, //比较规则,less升序,greater降序
class Alloc = allocator<T> //set中元素空间的管理方式
>
class set;
compare
:比较器的类型,set
中的元素是按照 value 来比较的,缺省情况下按照小于来比较,一般情况下 (内置类型元素) 该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则,一般情况下有两种传递方式:函数指针、仿函数;bool fncomp (int lhs, int rhs) {return lhs<rhs;}
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
set<int,classcomp> fifth;
bool(*fn_pt)(int,int) = fncomp;
set<int,bool(*)(int,int)> sixth (fn_pt);
set<数据类型> s;
:构造空的set
对象;set<数据类型> s(const set& x);
:用一个构造好的set
对象拷贝构建一个set
对象,数据类型要保持一致;set
对象,数据类型保持一致;template<class T>
set<数据类型> s(T first, T last);
set
对象的另一种方式是使用初始化列表来指定初始值以及元素个数,可以用等号后面加花括号来输入参数,也可以直接在变量名后加花括号来输入参数,如果是自定义类型,那么输入的参数则是构造函数(参数)
的形式;struct A{
A(int a = 1, int b = 2)
:_a(a)
,_b(b)
{}
int _a;
int _b;
};
//内置类型
set<int> s1 = {1, 2, 3};
set<int> s2{1, 2, 3};
//自定义类型
set<A> s3 = {A(1, 2), A(3, 4)};
set<A> s4{A(1, 2), A(3, 4)};
set
容器的迭代器在使用上和string
容器的迭代器是基本一样的,只需将string
中的每个字符替换为set
中的每个元素即可,因此就不做过多介绍,这里附上string
容器的迭代器的介绍以及set
容器的迭代器的网上详细定义;
set
中的元素关键码和数据值相同,因此不允许直接修改,所以迭代器中的const
类迭代器与非const
类迭代器的使用是一样的:只可读,不可写;set
容器底部的结构是和二叉搜索树类似的红黑树,因此如果使用迭代器对set
对象进行遍历的话,那么将会有序的将对象中的数据打印出来;bool empty ( ) const;
:检测set
是否为空,为空返回 true,否则返回 false;size_type size() const;
:返回set
中有效元素的个数;size_type max_size() const;
:返回可以使用的最大空间,这和底层的空间适配器有关;pair insert(const value_type& x);
:在set
中插入元素 x,实际插入的是 pair
类型的键值对:<该元素在set中的迭代器位置, true>,如果插入失败,说明 x 在set
中已经存在,返回一个pair
类型的键值对:iterator insert (iterator position, const value_type& val);
:在指定迭代器的位置插入数据 val,但是该迭代器位置只是一个建议,底层听不听从得看插入位置是否满足set
的大小关系性质,所以最终插入位置不定,成功则返回插入后的位置,失败则说明 val 在set
中已经存在,所以返回 val 在set
中存在的迭代器位置;set
对象中;template <class InputIterator>
void insert (InputIterator first, InputIterator last);
void erase (iterator position);
:删除指定迭代器位置的元素,迭代器位置不能传入非法值;size_type erase (const value_type& val);
:删除指定数据的结点,返回值代表了删除了多少个等于 val 的值,一般为 0 或 1,0 代表删除失败,1 代表删除成功;void erase (iterator first, iterator last);
:删除指定迭代器区间中的元素,迭代器位置不能传入非法值;void swap (set& x);
:交换两个set
对象的数据;void clear();
:清空set
对象的内容;insert
函数一样;template <class... Args>
pair<iterator,bool> emplace (Args&&... args);
insert
函数一样;template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);
iterator find (const value_type& val);
:查找指定数据 val 是否存在,如果存在则返回数据的迭代器,如果不存在则返回end
迭代器;size_type count (const value_type& val) const;
:查找指定数据 val 在set
对象中的个数,因为set
的关键码与数据值相同,所以数据不会重复出现,所以返回值只能为 1 或 0;map
map
是关联容器,它按照特定的次序 (按照 key 来比较) 存储由键值 key 和值 value 组合而成的键值对;map
中,键值 key 通常用于排序和唯一地标识元素,而数据值 value 中存储与对应键值 key 关联的内容,键值 key 和数据值 value 的类型可以不同,并且 value 值可以重复;map
内部中的元素总是按照键值 key 进行比较排序的;map
中通过键值访问单个元素的速度通常比unordered_map
容器慢,但map
允许根据顺序对元素进行直接迭代 (即对map
中的元素进行迭代时,可以得到一个有序的序列);map
支持下标访问符,即在[]
中放入 key,就可以找到与 key 对应的 value;map
通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树));map
时需要包含
头文件;template < class Key, // key数据类型
class T, // val数据类型
class Compare = less<Key>, // 比较规则,与set类似
class Alloc = allocator<pair<const Key,T> > // 底层容器分配
>
class map;
compare
:比较器的类型,map
中的元素是按照 key 来比较的,缺省情况下按照小于来比较,一般情况下 (内置类型元素) 该参数不需要传递,如果无法比较时(自定义类型),需要用户自己显式传递比较规则,一般情况下有两种传递方式:函数指针、仿函数;bool fncomp (char lhs, char rhs) {return lhs<rhs;}
struct classcomp {
bool operator() (const char& lhs, const char& rhs) const
{return lhs<rhs;}
};
map<char,int,classcomp> fourth;
bool(*fn_pt)(char,char) = fncomp;
map<char,int,bool(*)(char,char)> fifth (fn_pt);
map<关键码类型, 数据值类型> m;
构造空的map
对象;map<关键码类型, 数据值类型> m(const map& mp);
:使用map
对象来拷贝构造出一个map
对象,数据类型要保持一致;map
对象,注意数据类型要保持一致;template<class T>
map<关键码类型, 数据值类型> m(T frist, T second);
bool fncomp (char lhs, char rhs) {return lhs<rhs;}
struct classcomp {
bool operator() (const char& lhs, const char& rhs) const
{return lhs<rhs;}
};
int main (){
map<char,int> first;
first['a']=10;
first['b']=30;
first['c']=50;
first['d']=70;
map<char,int> second (first.begin(),first.end());
map<char,int> third (second);
map<char,int,classcomp> fourth; // class as Compare
map<char,int,bool(*)(char,char)> fifth (fncomp); // function pointer as Compare
return 0;
}
map
对象的另一种方式是使用初始化列表来指定初始值以及元素个数,可以用等号后面加花括号来输入参数,也可以直接在变量名后加花括号来输入参数,如果是自定义类型,那么输入的参数则是构造函数(参数)
的形式;struct A {
A(int a = 1, int b = 2)
:_a(a)
, _b(b)
{}
int _a;
int _b;
};
//内置类型
map<int, int> m1 = { {1, 2}, {2, 3}, {3, 9}, {4, 2} };
map<int, int> m2{ {1, 2}, {2, 3}, {3, 9}, {4, 2} };
//自定义类型
map<A, int> m3 = { {A(1, 2), 4}, {A(3, 4), 5}, {A(4, 2), 4} };
map<A, int> m4{ {A(1, 2), 4}, {A(3, 4), 5}, {A(4, 2), 4} };
map
容器的迭代器在使用上和string
容器的迭代器是基本一样的,只需将string
中的每个字符替换为map
中的每个元素即可,因此就不做过多介绍,这里附上string
容器的迭代器的介绍以及map
容器的迭代器的网上详细定义;
map
中 key 是唯一的,而 value 并不是唯一的,因此 value 值可以重复存储,并且可以对非const
的迭代器的second
成员变量进行修改,而const
的迭代器仍不可以修改;map
容器底部的结构是和二叉搜索树类似的红黑树,但是如果使用迭代器对map
对象进行遍历的话,那么只会将键值 key 有序的打印出来,而 value 的顺序未知;bool empty ( ) const;
:检测map
是否为空,为空返回 true,否则返回 false;size_type size() const;
:返回map
中有效元素的个数;size_type max_size() const;
:返回可以使用的最大空间,这和底层的空间适配器有关;mapped_type& at (const key_type& k);
:对于map
对象,可以访问已存在的 key 值所对应的 value 值,并且可以修改已存在的 key 值所对应的 value 值,而对于不存在的 key 值的访问会抛异常;mapped_type& operator[] (const key_type& k);
:对于map
对象,可以访问已存在的 key 值所对应的 value 值,并且可以修改已存在的 key 值所对应的 value 值,而对于不存在的 key 值的访问则会创建一个map
元素,并将其 value 值设置成你所要修改的值(如果只是访问而没有修改,则会设置为默认值),然后插入其中;[]
的访问操作的原理:[]
操作其实等价于(*((this->insert(make_pair(k,mapped_type()))).first)).second
;pair insert (const value_type& val);
:插入一个pair
键值对,键值对的表示方法有两种pair(key, value)
或者make_pair(key, value)
,如果插入成功,返回一个pair
类型的键值对:<该元素在map中的迭代器位置, true>,如果插入失败,说明 key 在map
中已经存在,返回一个pair
类型的键值对:iterator insert (iterator position, const value_type& val);
:在指定迭代器位置插入一个pair
键值对,方式有两种,同上,成功则返回插入后的位置,失败则说明 key 在map
中已经存在,所以返回 key 在map
中存在的迭代器位置;map
对象中;template <class InputIterator>
void insert(InputIterator first, InputIterator last);
void erase (iterator position);
:删除指定迭代器位置的元素,迭代器位置不能传入非法值;size_type erase (const key_type& k);
:删除指定 key 值的结点,返回值代表了删除了多少个 key 值等于 k 的元素,一般为 0 或 1,0 代表删除失败,1 代表删除成功;void erase (iterator first, iterator last);
:删除指定迭代器区间中的元素,迭代器位置不能传入非法值;void swap (set& x);
:交换两个map
对象的数据;void clear();
:清空map
对象的内容;insert
函数一样;template <class... Args>
pair<iterator,bool> emplace (Args&&... args);
insert
函数一样;template <class... Args>
iterator emplace_hint (const_iterator position, Args&&... args);
iterator find (const key_type& k);
:查找指定关键码 key 是否存在,如果存在则返回该键值对的迭代器,如果不存在则返回end
迭代器;size_type count (const key_type& k) const;
:查找指定关键码 key 在map
对象中的个数,因为map
的关键码 key 不会重复出现,所以返回值只能为 1 或 0;multiset
multiset
是按照特定顺序存储元素的容器,其中元素是可以重复的;multiset
中,元素的 value 也可以用来识别它 (因为multiset
中本身存储的就是 multiset
元素的值不能在容器中进行修改 (因为元素总是const
的),但可以从容器中插入或删除。multiset
中的元素总是按照其内部比较规则 (数据类型的比较规则) 所指示的特定严格弱排序准则进行排序;multiset
容器通过 key 访问单个元素的速度通常比unordered_multiset
容器慢,但当使用迭代器遍历时会得到一个有序序列;multiset
底层结构为二叉搜索树(红黑树);multiset
与set
的使用基本没有什么区别,只是multiset
中可以存储相同的元素而已;multimap
Multimaps
是关联式容器,它按照特定的顺序,存储由 key 和 value 映射成的键值对 multimap
中,通常按照 key 排序并且按照 key 唯一地标识元素,而 value 存储与 key 关联的内容,key 和 value 的类型可能不同;multimap
中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对 key 进行排序的;multimap
通过 key 访问单个元素的速度通常比unordered_multimap
容器慢,但是使用迭代器直接遍历multimap
中的元素可以得到关于 key 有序的序列;multimap
在底层用二叉搜索树(红黑树)来实现;multimap
与map
的使用基本相似,有两点不同:
multimap
中的 key 是可以重复的;multimap
中没有重载operator[]
操作,因为 key 值不唯一,所以会产生二义性;set
注意点set
与map / multimap
不同,map / multimap
中存储的是真正的键值对 set
中只放 value,但在底层实际存放的是由 set
中插入元素时,只需要插入 value 即可,不需要构造键值对;set
中的元素不可以重复 (因此可以使用set
进行去重),所以set
重元素不能修改;set
的迭代器遍历set
中的元素,可以得到有序序列;set
中的元素默认按照小于来比较;set
中查找某个元素,时间复杂度为:log2n;map
注意点map
中的的元素是键值对;map
中的 key 是唯一的,并且不能修改;map
中的元素如果用迭代器去遍历,可以得到一个有序的序列;map
中查找某个元素,时间复杂度为:log2n;[]
操作符,operator[]
中实际进行创建插入查找;