24 容器
24.1 容器概念分类
container, sequence container, and associative container
24.2 容器类型分类
原来的11种:deque, list, queue, priority_queue, stack, vector, map, multimap, set, multiset, and bitset C++11添加:forward_list, unordered_map, unordered_multimap, unordered_set, and unordered_multiset
24.3 容器概念
定义:容器概念实际上是一种概念性抽象基类-本质上容器概念不使用继承机制。 容器实际上是一个对象存储了其他的对象,他们都是独立的类型 存储在容器中的对象属于容器,如果容器释放了,那么其中的对象也释放了(如果是指针容器的话,指向的内容可能没有释放) 条件:只有有复制构造函数和赋值操作符重载的对象才可以存储到容器中。 特点:基础容器不保证存储元素有序或存储顺序不变(但是改进的概念可能添加这些保证)
右边的复杂性描述了执行操作所需要的时间复杂性,编译时间==>常量时间==>线性时间,从左到右从快到慢。 编译时间复杂性:操作是在编译时执行的,运行时不执行 常量时间复杂性:不依赖于对象中的元素数 线性时间复杂性:时间与元素数量呈正比
基础容器的属性:X是容器类型,T是存储在X中的对象类型,a和b是X的值,r是X&的值,u表示类型为X的对象(如果X为vector<int>,则u是vector<int>对象)
表达式 | 返回值 | 描述 | 时间复杂性 |
---|---|---|---|
X::iterator | 指向T的迭代器 | 满足前向迭代器要求的任何迭代器类别 | 编译时间 |
X::value_type | T | T的类型 | 编译时间 |
X u; | 创建一个空容器u | 常量 | |
X(); | 创建一个匿名的空容器 | 常量 | |
X u(a); | 复制构造函数创造一个和a相等的容器u | 线性 | |
X u = a; | 作用和X u(a);一样 | 线性 | |
r = a; | X& | 赋值操作符,使得r=a | 线性 |
(&a)->~X(); | void | 对容器中每个元素都执行析构函数 | 线性 |
a.begin() | 迭代器 | 返回一个指向第一个元素的迭代器 | 常量 |
a.end() | 迭代器 | 返回一个指向最后一个元素的后一个元素的迭代器 | 常量 |
a.size() | 无符号迭代器 | 返回容器中元素的数量,等价于a.end() - a.begin() | 常量 |
a.swap(b) | void | 交换a,b的内容 | 常量 |
a == b | bool | 当a==b(元素数量和内容都相等)返回true,反之返回false | 线性 |
a != b | bool | 当a!=b(元素数量和内容都相等)返回true,反之返回false | 线性 |
C++11添加的新属性:rv是一个X类型的非常量右值
X u(rv); | 移动构造函数后置条件:u 具有 rv 之前的值 | 线性 | |
---|---|---|---|
X u = rv; | 和X u(rv);有同样的作用 | 线性 | |
a = rv; | X& | 移动赋值后置条件:a 具有 rv 之前具有的值 | 线性 |
a.cbegin() | 常量迭代器 | 返回指向容器第一个元素的const迭代器 | 常量 |
a.cend() | 常量迭代器 | 返回指向容器最后一个元素的后一个元素的const迭代器 | 常量 |
24.4 序列
可以给容器概念添加要求。 序列分类:deque, forward_list(C++11), list, queue, priority_queue, stack,vector,array 序列比容器概念更多的要求: 1.迭代器至少是正向迭代器以上,保证元素被放置在一个明确的位置(而不随这遍历的变化而变化) 2.元素必须是线性存放的,像树、图就不行 序列的属性:X是容器类型,T是存储在X中的对象类型,a和b是X的值,r是X&的值,u表示类型为X的对象(如果X为vector<int>,则u是vector<int>对象),t代表T的一个值,n是一个整型,p,q,i,j是迭代器
表达式 | 返回值 | 描述 |
---|---|---|
X a(n,t); | 定义一个长度为n,元素全为t的序列a | |
X(n, t) | 定义一个长度为n,元素全为t的匿名序列 | |
X a(i, j) | 定义一个用[i,j)范围内的元素初始化的序列a | |
X(i, j) | 定义一个用[i,j)范围内的元素初始化的匿名序列 | |
a.insert(p,t) | 迭代器 | 在p元素之前插入元素t |
a.insert(p,n,t) | void | 在p元素之前插入n个t |
a.insert(p,i,j) | void | 在p元素之前插入[i,j)范围内的元素 |
a.erase(p) | 迭代器 | 删除p指向的元素 |
a.erase(p,q) | 迭代器 | 删除[p,q)范围内的元素 |
a.clear() | void | 删除所有元素 |
还有一些属性,有些序列支持,有些序列不支持,这些属性都拥有常量时间复杂度
表达式 | 返回值 | 含义 | 容器 |
---|---|---|---|
a.front() | T& | *a.begin() | vector, list, deque |
a.back() | T& | *a.end() | vector, list, deque |
a.push_front(t) | void | a.insert(a.begin(), t) | list, deque |
a.push_back(t) | void | a.insert(a.end(), t) | vector, list, deque |
a.pop_front(t) | void | a.erase(a.begin()) | list, deque |
a.pop_back(t) | void | a.erase(a.end()) | vector, list, deque |
a[n] | T& | *(a.begin() + n) | vector, deque |
a.at(n) | T& | *(a.begin() + n) | vector, deque |
a[n]与a.at(n)的不同在于a.at(n)会检查是否越界,如果访问的元素越界,则抛出out_of_range异常
24.4.1 vector
定义头文件:vector头文件 特点: 1.随机访问 2.插入或移除最后一个元素是常量时间复杂度,但是插入或移除开头或中间的元素是线性时间复杂度。 3.允许逆向访问:rbegin()函数返回指向逆序的第一个元素的逆向迭代器,rend()函数指向逆序的最后一个元素后一个元素的逆向迭代器。 4.vector被认为是最简单的序列,使用时首先考虑使用vector,但如果需要其他序列的特性的话考虑使用其他序列。
24.4.2 deque
定义头文件:deque 特点: 1.随机访问 2.双向队列,插入或移除开头和结尾的元素是常量复杂度(Vector是线性复杂度),其他和vector一样 3.由于实现了双向,所以设计实现比vector更复杂,因此deque执行插入或移除操作比vector慢
24.4.3 list
定义头文件:list 特点: 1.双向链表,除开头节点和尾节点,其他节点与他前面的和后面的节点都是相互联系的,可以双向遍历list 2.与vector和deque最大的不同是,在任意位置插入或移除元素都是常量时间复杂度 3.list强调快速插入或删除,vector和deque强调快速访问 4.不支持随机访问和数组下标访问元素 5.即使插入或移除元素,list迭代器指向的元素不变,不移动已存在的元素,但是会改变链接关系 一些list类模板的成员函数:
Function | Description |
---|---|
void merge(list<T, Alloc>& x) | 将列表x与调用列表合并。前提是两个列表已排序。生成的排序列表位于调用列表中,x留空。此函数具有线性时间复杂性。 |
void remove(const T & val) | 从列表中删除所有的val。此函数具有线性时间复杂性。 |
void sort() | 使用<运算符对列表进行排序;对于N个元素,时间复杂度为NlogN。有成员方法sort()的原因是list不支持随机访问,因此不能使用非成员方法sort() |
void splice(iterator pos, list<T, Alloc> x) | 将列表x的内容插入到位置pos的前面,并且x留空。此函数具有常量时间复杂性。 |
void unique() | 将每个连续的相等元素组折叠为单个元素。此函数具有线性时间复杂性。 |
24.4.4 forward_list (C++11)
特点: 1.单向列表,每个元素只与后面的元素相链接,而不与前面的元素相链接 2.只需要正向迭代器而不需要反向迭代器 3.与list相比,forward_list更简单,但是更少的特征
24.4.5 queue
定义头文件:queue 特点: 1.是一个适配类---queue模板允许基础类(默认情况下为 deque)显示典型的队列接口 2.不允许随机访问,不允许循环遍历队列 3.限制使用操作访问元素,只允许在队尾添加元素、在队首删除元素、查看队尾或队首的元素、计算有多少元素、检查队列是否为空。 4.如果想要使用队列的一个值,首先使用front()获取到值,然后再使用pop()将该值从队列中移除。 一些queue类模板的成员函数:
Method | Description |
---|---|
bool empty() const | Returns true if the queue is empty and false otherwise. |
size_type size() const | Returns the number of elements in the queue. |
T& front() | Returns a reference to the element at the front of the queue. |
T& back() | Returns a reference to the element at the back of the queue. |
void push(const T& x) | Inserts x at the back of the queue. |
void pop() | Removes the element at the front of the queue. |
24.4.6 priority_queue
定义头文件:queue 特点: 1.是一个适配类---默认的基础类是vector 2.支持所有的queue操作,但是priority_queue的最大的元素(可以修改决定最大元素的算法)移到了队列的前面
24.4.7 stack
定义头文件:stack 特点: 1.是一个适配器,其基础类是vector(适配器就是相当于充电器,将220V转换为低电压以适配手机充电。由于基础类太泛化,因此设计满足特定需求的适配器) 2.不允许随机访问,不允许循环遍历栈 3.可以向栈顶插入元素,从栈顶弹出元素,查看栈顶的元素,计算元素个数,检查栈是否为空 4.当需要使用栈中的值时,首先使用top()获取到该值,然后使用pop()将该值从栈中弹出 一些stack的成员函数:
Method | Description |
---|---|
bool empty() const | Returns true if the stack is empty and false otherwise. |
size_type size() | const Returns the number of elements in the stack. |
T& top() | Returns a reference to the element at the top of the stack. |
void push(const T& x) | Inserts x at the top of the stack. |
void pop() R | Removes the element at the top of the stack. |
24.4.8 array(C++11)
定义头文件:array 特点: 1.由于array具有固定大小,所以不是STL容器 2.会修改容器大小的成员函数如puch_back(),insert(),array无法使用 3.但是容器成员函数operator,at()允许使用 4.STL算法copy(),for_each()允许使用
24.5 关联容器
将键值与值联系到一起,并且使用键值去寻找值;X::key_type指示了键值的类型 特点:可以快速访问元素;关联容器允许插入新元素,但是不能指定插入元素的存储位置,原因是关联容器有特定的算法决定将元素插入到哪里,有助于快速获取信息。 如何实现关联容器的?使用树实现的,树是一种数据结构根节点链接一个或多个子节点,子节点又链接一个或多个子节点,形成一个分支结构;这种链接结构使得容器删除或添加元素,同时访问速度也较快。 四种关联容器:set, multiset, map, and multimap.
24.5.1 set
实现头文件:set 特点: 1.值和键值的数据类型一样,而且键值是唯一的,值就是键,相当于数学上的集合(一个集合中不会出现相等的元素)。 2.是一个关联容器,是可逆的,是排序的,键值是唯一的,不允许存在相同的值 3.set使用模板参数指示存储的类型 set<string> A; // a set of string objects 4.有一个模板可选参数用于指定排序时使用的比较函数,默认是less<>(旧版本的C++没有默认值,需要自己指定) set<string, less<string> > A; // older implementation 成员函数:
Method | Description |
---|---|
set(i,j) | 初始化一个set为[i,j)范围内的元素 |
insert(var); | 向set中插入元素var,并排序 |
lower_bound(val) | 返回指向小于等于指定val的第一个元素的迭代器 |
upper_bound(val) | 返回指向大于指定val的第一个元素的迭代器 |
非成员函数:
Method | Description |
---|---|
set_union(范围1始, 范围1末, 范围2始, 范围2末, 目标set) | 将范围1和范围2的元素合并起来插入到目标set,并排序 |
copy(范围始, 范围末, 目标set); | 将范围中的元素复制到目标set(是覆盖),前提是目标set有足够的存储空间 |
set_intersection(范围1始, 范围1末, 范围2始, 范围2末, 目标set); | 将范围1和范围2的交集插入到目标set,并排序 |
set_difference(范围1始, 范围1末, 范围2始, 范围2末, 目标set); | 将范围1与范围2的差集集插入到目标set,并排序 |
24.5.2 multiset
实现头文件:set 特点: 1.值和键值的数据类型一样,并且键值是唯一的 2.一个键值可以对应多个值
24.5.3 map
实现头文件:map 特点: 1.值类型与键值类型不一样,键值唯一,每个键值只有一个值
24.5.4 multimap
实现头文件:map 特点: 1.值类型和键值类型不一样,键值唯一,每个键值可以又多个值。 2.是关联容器,是可逆的,是排序的 3.multimap<KeyType,ValueType,comparison_func=less<>模板> var; 4.pair<class T, class U> template class将keyValue和Value联合到一起,可以使用下面的方法添加元素 pair<const int, string> item(213, "Los Angeles"); multimap.insert(item); codes.insert(pair<const int, string> (213, "Los Angeles")); 5.pair只能包含两个元素,要想实现1个key包含多个value,则多次插入键值相同值不同的pair 成员函数:
Method | Description |
---|---|
count(key) | 检查键值为key有多少个值 |
insert(pair); | 向set中插入键值对pair,并按键值排序 |
lower_bound(key) | 返回指向小于等于指定key的第一个元素的迭代器 |
upper_bound(key) | 返回指向大于指定key的第一个元素的迭代器 |
equal_range(key) | 返回匹配指定key的迭代器范围,该范围pair<multimap<KeyType, string>::iterator,multimap<KeyType, string>::iterator> range表示 |
24.6 无序关联容器
Unordered Associative Containers (C++11)
特点: 1.将键值与值相关联并使用键值去寻找值 2.基于数据结构哈希表 3.提出无序关联容器的目的是提供相对较快的查询、删除或添加元素的容器。 4.四种无序关联容器:unordered_set,unordered_multiset, unordered_map, and unordered_multimap
24.7 举例
main.cpp
/* Project name : _23Containers Last modified Date: 2022年4月9日16点52分 Last Version: V1.0 Descriptions: 容器 */ /* 容器概念分类:container, sequence container, and associative container 容器类型分类: 原来的11种:deque, list, queue, priority_queue, stack, vector, map, multimap, set, multiset, and bitset C++11添加:forward_list, unordered_map, unordered_multimap, unordered_set, and unordered_multiset */ /* 容器概念: 定义:容器概念实际上是一种概念抽象基类-本质上容器概念不使用继承机制。 容器实际上是一个对象存储了其他的对象,他们都是独立的类型 存储在容器种的对象属于容器,如果容器释放了,那么其中的对象也释放了(如果是指针容器的话,指向的内容可能没有释放) 条件:只有有复制构造函数和赋值操作符重载的对象才可以存储到容器中。 特点:基础容器不保证存储元素有序或存储顺序不变(但是改进的概念可能添加这些保证) 右边的复杂性描述了执行操作所需要的时间复杂性,编译时间==>常量时间==>线性时间,从左到右从快到慢。 编译时间复杂性:操作是在编译时执行的,运行时不执行 常量时间复杂性:不依赖于对象中的元素数 线性时间复杂性:时间与元素数量呈正比 基础容器的属性:X是容器类型,T是存储在X中的对象类型,a和b是X的值,r是X&的值,u表示类型为X的对象(如果X为vector<int>,则u是vector<int>对象) 表达式 返回值 描述 时间复杂性 X::iterator 指向T的迭代器 满足前向迭代器要求的任何迭代器类别 编译时间 X::value_type T T的类型 编译时间 X u; 创建一个空容器u 常量 X(); 创建一个匿名的空容器 常量 X u(a); 复制构造函数创造一个和a相等的容器u 线性 X u = a; 作用和X u(a);一样 线性 r = a; X& 赋值操作符,使得r=a 线性 (&a)->~X(); void 对容器中每个元素都执行析构函数 线性 a.begin() 迭代器 返回一个指向第一个元素的迭代器 常量 a.end() 迭代器 返回一个指向最后一个元素的后一个元素的迭代器 常量 a.size() 无符号迭代器 返回容器中元素的数量,等价于a.end() - a.begin() 常量 a.swap(b) void 交换a,b的内容 常量 a == b bool 当a==b(元素数量和内容都相等)返回true,反之返回false 线性 a != b bool 当a!=b(元素数量和内容都相等)返回true,反之返回false 线性 C++11添加的新属性:rv是一个X类型的非常量左值 X u(rv); 移动构造函数后置条件:u 具有 rv 之前的值 线性 X u = rv; 和X u(rv);有同样的作用 a = rv; X& 移动赋值后置条件:a 具有 rv 之前具有的值 线性 a.cbegin() 常量迭代器 返回指向容器第一个元素的const迭代器 常量 a.cend() 常量迭代器 返回指向容器最后一个元素的后一个元素的const迭代器 常量 序列: 可以给容器概念添加要求。 序列分类:deque, forward_list(C++11), list, queue, priority_queue, stack,vector,array 序列比容器概念更多的要求: 1.迭代器至少是正向迭代器以上,保证元素被放置在一个明确的位置(而不随这遍历的变化而变化) 2.元素必须是线性存放的,像树、图就不行 序列的属性:X是容器类型,T是存储在X中的对象类型,a和b是X的值,r是X&的值,u表示类型为X的对象(如果X为vector<int>,则u是vector<int>对象) t代表T的一个值,n是一个整型,p,q,i,j是迭代器 表达式 返回值 描述 X a(n,t); 定义一个长度为n,元素全为t的序列a X(n, t) 定义一个长度为n,元素全为t的匿名序列 X a(i, j) 定义一个用[i,j)范围内的元素初始化的序列a X(i, j) 定义一个用[i,j)范围内的元素初始化的匿名序列 a.insert(p,t) 迭代器 在p元素之前插入元素t a.insert(p,n,t) void 在p元素之前插入n个t a.insert(p,i,j) void 在p元素之前插入[i,j)范围内的元素 a.erase(p) 迭代器 删除p指向的元素 a.erase(p,q) 迭代器 删除[p,q)范围内的元素 a.clear() void 删除所有元素 还有一些属性,有些序列支持,有些序列不支持,这些属性都拥有常量时间复杂度 表达式 返回值 含义 容器 a.front() T& *a.begin() vector, list, deque a.back() T& *a.end() vector, list, deque a.push_front(t) void a.insert(a.begin(), t) list, deque a.push_back(t) void a.insert(a.end(), t) vector, list, deque a.pop_front(t) void a.erase(a.begin()) list, deque a.pop_back(t) void a.erase(a.end()) vector, list, deque a[n] T& *(a.begin() + n) vector, deque a.at(n) T& *(a.begin() + n) vector, deque a[n]与a.at(n)的不同在于a.at(n)会检查是否越界,如果访问的元素越界,则抛出out_of_range异常 vector 定义头文件:vector头文件 特点: 1.随机访问 2.插入或移除最后一个元素是常量时间复杂度,但是插入或移除开头或中间的元素是线性时间复杂度。 3.允许逆向访问:rbegin()函数返回指向逆序的第一个元素的逆向迭代器,rend()函数指向逆序的最后一个元素后一个元素的逆向迭代器。 4.vector被认为是最简单的序列,使用时首先考虑使用vector,但如果需要其他序列的特性的话考虑使用其他序列。 deque 定义头文件:deque 特点: 1.随机访问 2.双向队列,插入或移除开头的元素是常量复杂度,其他和vector一样 3.由于实现了双向,所以比vector更复杂,因此在中间或尾部插入或移除元素比vector慢 list 定义头文件:list 特点: 1.双向链表,除开头节点和尾节点,其他节点与他前面的和后面的节点都是相互联系的,可以双向遍历list 2.与vector和deque最大的不同是,在任意位置插入或移除元素都是常量时间复杂度 3.list强调快速插入或删除,vector和deque强调快速访问 4.不支持随机访问和数组下标访问元素 5.即使插入或移除元素,list迭代器指向的元素不变,不移动已存在的元素,但是会改变链接关系 一些list类模板的成员函数: Function Description void merge(list<T, Alloc>& x) 将列表x与调用列表合并。前提是两个列表已排序。生成的排序列表位于调用列表中,x留空。此函数具有线性时间复杂性。 void remove(const T & val) 从列表中删除所有的val。此函数具有线性时间复杂性。 void sort() 使用<运算符对列表进行排序;对于N个元素,时间复杂度为NlogN 有成员方法sort()的原因是list不支持随机访问,因此不能使用非成员方法sort() void splice(iterator pos, list<T, Alloc> x) 将列表x的内容插入到位置pos的前面,并且x留空。此函数具有常量时间复杂性。 void unique() 将每个连续的相等元素组折叠为单个元素。此函数具有线性时间复杂性。 forward_list (C++11) 特点: 1.单向列表,每个元素只与后面的元素相链接,而不与前面的元素相链接 2.只需要正向迭代器而不需要反向迭代器 3.与list相比,forward_list更简单,但是更少的特征 queue 定义头文件:queue 特点: 1.是一个适配类---queue模板允许基础类(默认情况下为 deque)显示典型的队列接口 2.不允许随机访问,不允许循环遍历队列 3.限制使用操作访问元素,只允许在队尾添加元素、在队首删除元素、查看队尾或队首的元素、计算有多少元素、检查队列是否为空。 4.如果想要使用队列的一个值,首先使用front()获取到值,然后再使用pop()将该值从队列中移除。 一些queue类模板的成员函数: Method Description bool empty() const Returns true if the queue is empty and false otherwise. size_type size() const Returns the number of elements in the queue. T& front() Returns a reference to the element at the front of the queue. T& back() Returns a reference to the element at the back of the queue. void push(const T& x) Inserts x at the back of the queue. void pop() Removes the element at the front of the queue. priority_queue 定义头文件:queue 特点: 1.是一个适配类---默认的基础类是vector 2.支持所有的queue操作,但是priority_queue的最大的元素(可以修改决定最大元素的算法)移到了队列的前面 stack 定义头文件:stack 特点: 1.是一个适配器,其基础类是vector(适配器就是相当于宇哥充电器,将220V转换为低电压以适配手机充电。由于基础类太泛化,因此设计满足特定需求的适配器) 2.不允许随机访问,不允许循环遍历栈 3.可以向栈顶插入元素,从栈顶弹出元素,查看栈顶的元素,计算元素个数,检查栈是否为空 4.当需要使用栈中的值时,首先使用top()获取到该值,然后使用pop()将该值从栈中弹出 一些stack的成员函数: Method Description bool empty() const Returns true if the stack is empty and false otherwise. size_type size() const Returns the number of elements in the stack. T& top() Returns a reference to the element at the top of the stack. void push(const T& x) Inserts x at the top of the stack. void pop() R emoves the element at the top of the stack. array(C++11) 定义头文件:array 特点: 1.由于array具有固定大小,所以不是STL容器 2.会修改容器大小的成员函数如puch_back(),insert(),array无法使用 3.但是容器成员函数operator[](),at()允许使用 4.STL算法copy(),for_each()允许使用 关联容器:将键值以值联系到一起,并且使用键值去寻找值;X::key_type指示了键值的类型 特点:可以快速访问元素;关联容器允许插入新元素,但是不能指定插入元素的存储位置,原因是关联容器有特定的算法决定将元素插入到哪里,有助于快速获取信息。 如何实现关联容器的?使用树实现的,树是一种数据结构根节点链接一个或多个子节点,子节点又链接一个或多个子节点,形成一个分支结构;这种链接结构使得容器 删除或添加元素,同时访问速度也较快。 四种关联容器:set, multiset, map, and multimap. set 实现头文件:set 特点: 1.值和键值的数据类型一样,而且键值是唯一的,值就是键,相当于数学上的集合(一个集合中不会出现相等的元素)。 2.是一个关联容器,是可逆的,是排序的,键值是唯一的,不允许存在相同的值 3.set使用模板参数指示存储的类型 set<string> A; // a set of string objects 4.有一个模板可选参数用于指定排序时使用的比较函数,默认是less<>(旧版本的C++没有默认值,需要自己指定) set<string, less<string> > A; // older implementation 成员函数: Method Description set(i,j) 初始化一个set为[i,j)范围内的元素 insert(var); 向set中插入元素var,并排序 lower_bound(val) 返回指向小于指定val的第一个元素的迭代器 upper_bound(val) 返回指向大于指定val的第一个元素的迭代器 非成员函数: Method Description set_union(范围1始, 范围1末, 范围2始, 范围2末, 目标set) 将范围1和范围2的元素合并起来插入到目标set,并排序 copy(范围始, 范围末, 目标set); 将范围中的元素复制到目标set(是覆盖),前提是目标set有足够的存储空间 set_intersection(范围1始, 范围1末, 范围2始, 范围2末, 目标set); 将范围1和范围2的交集插入到目标set,并排序 set_difference(范围1始, 范围1末, 范围2始, 范围2末, 目标set); 将范围1与范围2的差集集插入到目标set,并排序 multiset 实现头文件:set 特点: 1.值和键值的数据类型一样,并且键值是唯一的 2.一个键值可以对应多个值 map 实现头文件:map 特点: 1.值类型与键值类型不一样,键值唯一,每个键值只有一个值 multimap 实现头文件:map 特点: 1.值类型和键值类型不一样,键值唯一,每个键值可以又多个值。 2.是关联容器,是可逆的,是排序的 3.multimap<KeyType,ValueType,comparison_func=less<>模板> var; 4.pair<class T, class U> template class将keyValue和Value联合到一起,可以使用下面的方法添加元素 pair<const int, string> item(213, "Los Angeles"); multimap.insert(item); codes.insert(pair<const int, string> (213, "Los Angeles")); 5.pair只能包含两个元素,要想实现1个key包含多个value,则多次插入键值相同值不同的pair 成员函数: Method Description count(key) 检查键值为k有多少个值 insert(pair); 向set中插入键值对pair,并按键值排序 lower_bound(key) 返回指向小于指定key的第一个元素的迭代器 upper_bound(key) 返回指向大于指定key的第一个元素的迭代器 equal_range(key) 返回匹配指定key的迭代器范围,该范围pair<multimap<KeyType, string>::iterator,multimap<KeyType, string>::iterator> range表示 Unordered Associative Containers (C++11)无序关联容器 特点: 1.将键值与值相关联并使用键值去寻找值 2.基于数据结构哈希表 3.提出无序关联容器的目的是提供相对较快的查询、删除或添加元素的条件 4.四种无序关联容器:unordered_set,unordered_multiset, unordered_map, and unordered_multimap */ // list.cpp -- using a list #include <iostream> #include <list> #include <iterator> #include <algorithm> #include<string> #include<set> #include<map> typedef int KeyType; typedef std::pair<const KeyType, std::string> Pair; typedef std::multimap<KeyType, std::string> MapCode; void outint(int n) { std::cout << n << " "; } int main() { using namespace std; cout << "sequence********************************************************************" << endl; list<int> one(5, 2); // list of 5 2s int stuff[5] = { 1,2,4,8, 6 }; list<int> two; two.insert(two.begin(), stuff, stuff + 5); int more[6] = { 6, 4, 2, 4, 6, 5 }; list<int> three(two); three.insert(three.end(), more, more + 6); cout << "List one: "; for_each(one.begin(), one.end(), outint);//List one: 2 2 2 2 2 cout << endl << "List two: "; for_each(two.begin(), two.end(), outint);//List two: 1 2 4 8 6 cout << endl << "List three: "; for_each(three.begin(), three.end(), outint);//List three: 1 2 4 8 6 6 4 2 4 6 5 three.remove(2); cout << endl << "List three minus 2s: "; for_each(three.begin(), three.end(), outint);//List three minus 2s: 1 4 8 6 6 4 4 6 5 three.splice(three.begin(), one); cout << endl << "List three after splice: "; for_each(three.begin(), three.end(), outint);//List three after splice: 2 2 2 2 2 1 4 8 6 6 4 4 6 5 cout << endl << "List one: "; for_each(one.begin(), one.end(), outint);//List one: three.unique(); cout << endl << "List three after unique: ";//List three after unique: 2 1 4 8 6 4 6 5 for_each(three.begin(), three.end(), outint); three.sort(); three.unique(); cout << endl << "List three after sort & unique: "; for_each(three.begin(), three.end(), outint);//List three after sort & unique: 1 2 4 5 6 8 two.sort(); three.merge(two); cout << endl << "Sorted two merged into three: "; for_each(three.begin(), three.end(), outint);//Sorted two merged into three: 1 1 2 2 4 4 5 6 6 8 8 cout << endl; cout << "Associative_Containers***************************************************" << endl; cout << "set******************************************************************" << endl; const int N = 6; string s1[N] = { "buffoon", "thinkers", "for", "heavy", "can", "for" }; string s2[N] = { "metal", "any", "food", "elegant", "deliver","for" }; set<string> A(s1, s1 + N); set<string> B(s2, s2 + N); ostream_iterator<string, char> out(cout, " "); cout << "Set A: "; copy(A.begin(), A.end(), out);//Set A: buffoon can for heavy thinkers cout << endl; cout << "Set B: "; copy(B.begin(), B.end(), out);//Set B: any deliver elegant food for metal cout << endl; cout << "Union of A and B:\n"; set_union(A.begin(), A.end(), B.begin(), B.end(), out);//any buffoon can deliver elegant food for heavy metal thinkers cout << endl; cout << "Intersection of A and B:\n"; set_intersection(A.begin(), A.end(), B.begin(), B.end(), out);//for cout << endl; cout << "Difference of A and B:\n"; set_difference(A.begin(), A.end(), B.begin(), B.end(), out);//buffoon can heavy thinkers cout << endl; set<string> C; cout << "Set C:\n"; set_union(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> >(C, C.begin())); copy(C.begin(), C.end(), out);//any buffoon can deliver elegant food for heavy metal thinkers cout << endl; cout << "Set D:\n"; set<string> D; set_intersection(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> >(D, D.begin())); copy(D.begin(), D.end(), out);//for cout << endl; cout << "Set E:\n"; set<string> E; set_difference(A.begin(), A.end(), B.begin(), B.end(), insert_iterator<set<string> >(E, E.begin())); copy(E.begin(), E.end(), out);//buffoon can heavy thinkers cout << endl; string s3("grungy"); C.insert(s3); cout << "Set C after insertion:\n"; copy(C.begin(), C.end(), out);//any buffoon can deliver elegant food for grungy heavy metal thinkers cout << endl; cout << "Showing a range:\n"; copy(C.lower_bound("ghost"), C.upper_bound("spook"), out);//grungy heavy metal cout << endl; cout << "multimap***************************************************************" << endl; MapCode codes; codes.insert(Pair(415, "San Francisco")); codes.insert(Pair(510, "Oakland")); codes.insert(Pair(718, "Brooklyn")); codes.insert(Pair(718, "Staten Island")); codes.insert(Pair(415, "San Rafael")); codes.insert(Pair(510, "Berkeley")); cout << "Number of cities with area code 415: " << codes.count(415) << endl;//Number of cities with area code 415: 2 cout << "Number of cities with area code 718: " << codes.count(718) << endl;//Number of cities with area code 718: 2 cout << "Number of cities with area code 510: " << codes.count(510) << endl;//Number of cities with area code 510: 2 cout << "lower_bound():" << endl; MapCode::iterator it; it = codes.lower_bound(718); cout << " " << (*it).first << " " << (*it).second << endl;// 718 Brooklyn cout << "upper_bound():" << endl; it = codes.upper_bound(510); cout << " " << (*it).first << " " << (*it).second << endl;// 718 Brooklyn cout << "Area Code City\n"; for (it = codes.begin(); it != codes.end(); ++it) cout << " " << (*it).first << " " << (*it).second << endl; /* Area Code City 415 San Francisco 415 San Rafael 510 Oakland 510 Berkeley 718 Brooklyn 718 Staten Island */ pair<MapCode::iterator, MapCode::iterator> range = codes.equal_range(718); cout << "Cities with area code 718:\n"; for (it = range.first; it != range.second; ++it) cout << (*it).second << endl; /* Cities with area code 718: Brooklyn Staten Island */ return 0; }
运行结果:
sequence******************************************************************** List one: 2 2 2 2 2 List two: 1 2 4 8 6 List three: 1 2 4 8 6 6 4 2 4 6 5 List three minus 2s: 1 4 8 6 6 4 4 6 5 List three after splice: 2 2 2 2 2 1 4 8 6 6 4 4 6 5 List one: List three after unique: 2 1 4 8 6 4 6 5 List three after sort & unique: 1 2 4 5 6 8 Sorted two merged into three: 1 1 2 2 4 4 5 6 6 8 8 Associative_Containers*************************************************** set****************************************************************** Set A: buffoon can for heavy thinkers Set B: any deliver elegant food for metal Union of A and B: any buffoon can deliver elegant food for heavy metal thinkers Intersection of A and B: for Difference of A and B: buffoon can heavy thinkers Set C: any buffoon can deliver elegant food for heavy metal thinkers Set D: for Set E: buffoon can heavy thinkers Set C after insertion: any buffoon can deliver elegant food for grungy heavy metal thinkers Showing a range: grungy heavy metal multimap*************************************************************** Number of cities with area code 415: 2 Number of cities with area code 718: 2 Number of cities with area code 510: 2 lower_bound(): 718 Brooklyn upper_bound(): 718 Brooklyn Area Code City 415 San Francisco 415 San Rafael 510 Oakland 510 Berkeley 718 Brooklyn 718 Staten Island Cities with area code 718: Brooklyn Staten Island D:\Prj\_C++Self\_23Containers\Debug\_23Containers.exe (进程 2172)已退出,代码为 0。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .