目录
一.容器介绍
二.键值对
三.树形结构关联式容器
3.1 set
3.1.1 set介绍
3.1.2 set的使用
3.2 map
3.2.1 map介绍
3.2.2 map使用
3.2.2 map中operator[]原理
3.2.3 用map记录次数
3.3multiset
3.3.1 multiset介绍
3.3.2 multiset使用
3.4 multiamp
3.4.1 multimap介绍
3.4.2使用
STL容器主要分为序列式容器和关联式的容器。
键值对是用来表示意义对应关系的一种结构,该结构一般只包含两个成员变量key和value。key代表键值,value代表与key对应的信息。一般就是知道key的值,来找value的值。
SGI-STL种关于键值对的定义:
template
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
//成员变量
first_type first;
second_type second;
//构造函数
pair()
:first(T1())
, second(T2())
{}
pair(const T1& a, const T2& b)
:first(a)
, second(b)
{}
};
其中结构体pair就代表键值对,pair种有两个成员变量first和second。first就对应key,second对应value。
根据应用场景的不同,STL一共实现了两种关联式容器:树形结构和哈希结构。
树形结构的关联式容器主要有四种:map,set,multiset和multimap。这四种容器的共同点为:底层结构都是使用平衡二叉树(红黑树),容器中的元素是一个有序序列。
T:set中存放元素的类型,实际底层存储
Compare:set中元素的比较方式的类型,默认less
Alloc:set中元素空间的管理方式,使用STL提供的空间配置器(内存池)管理。
注意:
使用set时必须加头文件#include
函数声明 | 功能介绍 |
explicit set(const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()) | 构造一个空set。比较方式和空间配置器都是缺省值。explicit关键字修饰不能发生类型转化 |
set(InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()) | 用迭代器[first,last)区间中的元素构造set,比较方式和空间配置器为缺省值。 |
set(const set& x) | set的拷贝构造函数,注意是深拷贝 |
set s1;
int array[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
//迭代器
set s2(array, array + sizeof(array) / sizeof(int));
//修改比较方式
set> s3(array, array + sizeof(array) / sizeof(int));
//拷贝构造
set s4(s2);
函数声明 | 功能介绍 |
iterator begin() | 返回set中起始位置元素的迭代器 |
iterator end() | 返回set中最后一个元素后面的迭代器 |
const_iterator cbegin()const | 返回set中起始位置元素的const迭代器,迭代器位置值不可以被修改 |
const_iterator cend()const | 返回set中最后一个元素后面的const迭代器,迭代器位置值不可以被修改 |
reverse_iterator rbegin() | 返回set中第一个元素的反向迭代器,即end()的前一个元素位置 |
reverse_iterator rend() | 返回set最后一个元素的下一个位置的反向迭代器,即begin()前一个元素位置。 |
const_reverse_iterator crbegin()const | 返回set中第一个元素的反向const迭代器,即cend()的前一个元素位置 |
const_reverse_iterator crend()const | 返回set最后一个元素的下一个位置的反向迭代器,即cbegin()前一个元素位置。 |
使用迭代器进行遍历
int main(){
int array[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
//迭代器
set s(array, array + sizeof(array) / sizeof(int));
//正向迭代
set::iterator it = s.begin();
while (it != s.end()){
cout << *it << " ";
it++;
}
cout << endl;
//反向迭代
set::reverse_iterator rit = s.rbegin();
while (rit != s.rend()){
cout << *rit << " ";
rit++;
}
cout << endl;
//范围for迭代
for (auto e : s){
cout << e << " ";
}
cout << endl;
getchar();
return 0;
}
输出:
支持迭代器遍历就支持范围for遍历,范围for底层用迭代器实现
函数声明 | 功能介绍 |
bool empty()const | 判断set是否为空,为空返回true,反之返回false |
size_type size()const | 返回set中有效元素个数 |
函数声明 | 功能介绍 |
pair |
再set中插入元素x,实际插的是 |
void erase(iterator position) | 删除set中position位置的值 |
size_type erase(const value_type& val) | 删除set中值为val的元素,返回删除元素的个数 |
void erase(iterator first, iterator last) | 删除set中[first,last)区间中的元素 |
void swap(set& x) | 交换set和x中的元素 |
void clear() | 将set中的元素清空 |
iterator find(const value_type& val) const | 在set中找打值为val元素的位置,没找到返回end()位置 |
size_type count(const value_type& val) const | 返回set中值为val的元素个数 |
注意:序列式容器中没有find函数,使用的是算法中的find,因为效率低。
int main(){
set s;
int array[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
int len = sizeof(array) / sizeof(array[0]);
//插入
for (int i = 0; i < len; i++){
s.insert(array[i]);
}
set::iterator it = s.find(3);
if (it != s.end()){//没找到返回end()位置,越界了
s.erase(it);//删除某一位置
}
s.erase(4);//删除某一值
s.erase(s.begin(), s.end());//删除区间值
int arr[] = { 15, 11, 12, 10 };
set s1(arr, arr + sizeof(arr) / sizeof(arr[0]));
s.swap(s1);//交换
s.clear();//清空
getchar();
return 0;
}
Key:键值对中key的类型
T:键值对中value的类型
Compare:比较器的类型,map中的元素是按照键值对中的key来比较的,缺省情况下按照小于(less)进行比较。一般情况下,内置类型该参数不需要进行传递,如果无法进行比较时(自定义类型),需要用户编写比较规则后,传递该参数,一般使用函数指针或者仿函数来传递。
Alloc:通过空间配置器来申请底层空间,不需要用户传递,除非用户不想使用标准库的空间配置器。
注意:
map使用时需要包含头文件#include
函数声明 | 功能介绍 |
explicit map(const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()) | 构造一个空map |
template map(InputIterator first, InputIterator last,const key_compare& comp = key_compare(),const allocator_type& alloc = allocator_type()); |
将区间[first,last)之间的数构造map |
map(const map& x) | 拷贝构造map,深拷贝 |
#include
#include
和set迭代器相同。
函数声明 | 功能介绍 |
iterator begin() | 返回起始位置元素的迭代器 |
iterator end() | 返回最后一个元素后面的迭代器 |
const_iterator cbegin()const | 返回起始位置元素的const迭代器,迭代器位置值不可以被修改 |
const_iterator cend()const | 返回最后一个元素后面的const迭代器,迭代器位置值不可以被修改 |
reverse_iterator rbegin() | 返回第一个元素的反向迭代器,即end()的前一个元素位置 |
reverse_iterator rend() | 返回最后一个元素的下一个位置的反向迭代器,即begin()前一个元素位置。 |
const_reverse_iterator crbegin()const | 返回第一个元素的反向const迭代器,即cend()的前一个元素位置 |
const_reverse_iterator crend()const | 返回最后一个元素的下一个位置的反向迭代器,即cbegin()前一个元素位置。 |
map遍历:
注意:map保存的是键值对,访问时,访问的时键值对结构体,需要用'.'和"->"操作符访问。
int main(){
//键值对数组,元素都是匿名对象
pair array[] = { pair(5, 1), pair(3, 1), pair(4, 1), pair(1, 1), pair(7, 1), pair(8, 1), };
map m(array, array + sizeof(array) / sizeof(array[0]));
map::iterator it = m.begin();
while (it != m.end()){
//因为保存的是键值对结构体pair,用'.'和'->'操作符访问
cout << it->first << ":" << it->second << endl;
//cout << (*it).first << ":" << (*it).second << endl;
it++;
}
//反向遍历
map::reverse_iterator rit = m.rbegin();
while (rit != m.rend()){
cout << rit->first << ":" << rit->second << endl;
rit++;
}
//范围for遍历
for (auto e : m){
cout << e.first << ":" << e.second << endl;
}
getchar();
return 0;
}
函数声明 | 功能介绍 |
bool empty()const | 检测map中元素是否为空,为空返回true,否则返回false |
size_type size()const | 返回map中有效元素的个数 |
再次说明,map是比较key来建立平衡二叉树的。
函数声明 | 功能介绍 |
pair |
再map中插入键值对x,注意x是一个键值对,返回值也是键值对。如果插入成功,返回<该元素在set中位置迭代器,true>,插入失败,说明已存在,返回 |
void erase(iterator position) | 删除map中position位置的值 |
size_type erase(const value_type& k) | 删除map中key值为k的元素,返回删除元素的个数 |
void erase(iterator first, iterator last) | 删除map中[first,last)区间中的元素 |
void swap(set& x) | 交换map和x中的元素 |
void clear() | 将map中的元素清空 |
iterator find(const value_type& k) const | 在map中找到key值为k元素的位置,没找到返回end()位置 |
size_type count(const value_type& k) const | 返回map键值key为k的元素个数 |
注意:map保存的时键值对,插入时需要构造键值对插入。
#include
#include
#include
#include
当键值key的k值存在map中时,返回的是键值对中value的引用。当键值key的k值不存在时,将该键值对
map的operator[]的实现是通过insert来实现的。
首先来了解map的nsert。
insert返回值也是一个键值对,
当插入的键值对val不存在时,插入成功,insert返回的键值对中,iterator代表插入成功的键值对在map中的位置,bool为true
当插入的键值对存在时,插入失败,insert返回的键值对中,iterator代表已存在键值对在map中的位置,bool为false。
总结operator[]原理:
由于operator[]是通过insert实现的如上
为什么不用find,find如果没有找到,返回值是end()迭代器,也不会实现插入。
总结operator[]作用:
一般operator[]用来插入和修改,不用来查找,因为不存在时会插入。
int main(){
string arr[] = { "苹果", "梨子", "西瓜", "苹果", "香蕉", "梨子", "苹果", "香蕉" };
map countMap;
//方法1
//利用find
for (auto str : arr){
map::iterator it = countMap.find(str);
if (it != countMap.end()){
it->second++;
}
else{
countMap.insert(make_pair(str, 1));
}
}
//方法2,利用insert
for (auto e : arr){
pair
注意:
1. multiset中再底层中存储的是
2. mtltiset的插入接口中只需要插入即可
3. 与set的区别是,multiset中的元素可以重复,set是中value是唯一的
4. 使用迭代器对multiset中的元素进行遍历,可以得到有序的序列
5. multiset中的元素不能修改
6. 在multiset中找某个元素,时间复杂度为O(logN)
7. multiset的作用:可以对元素进行排序
8.使用时与set包含头文件相同
此处只简单演示set与multiset的不同,其他接口接口与set相同
#include
#include
using namespace std;
int main(){
int arr[] = { 2, 1, 3, 9, 6, 0, 5, 8, 4, 7, 3, 4, 3 };
multiset ms;
set m;
for (auto e : arr){
ms.insert(e);
m.insert(e);
}
//遍历set
for (auto e : m){
cout << e << " ";
}
cout << endl;
//遍历multiset
for (auto e : ms){
cout << e << " ";
}
cout << endl;
getchar();
return 0;
}
输出:
multimap和map基本相同,主要的不同是map键值对中的key是不可以重复的,multimap中键值对中的key是可以重复的。
注意:
#include
#include
输出: