【C++】容器

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_typeTT的类型编译时间
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 == bbool当a==b(元素数量和内容都相等)返回true,反之返回false线性
a != bbool当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)voida.insert(a.begin(), t)list, deque
a.push_back(t)voida.insert(a.end(), t)vector, list, deque
a.pop_front(t)voida.erase(a.begin())list, deque
a.pop_back(t)voida.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类模板的成员函数:

FunctionDescription
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类模板的成员函数:

MethodDescription
bool empty() constReturns true if the queue is empty and false otherwise.
size_type size() constReturns 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的成员函数:

MethodDescription
bool empty() constReturns 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() RRemoves 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 成员函数:

MethodDescription
set(i,j)初始化一个set为[i,j)范围内的元素
insert(var);向set中插入元素var,并排序
lower_bound(val)返回指向小于等于指定val的第一个元素的迭代器
upper_bound(val)返回指向大于指定val的第一个元素的迭代器

非成员函数:

MethodDescription
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 成员函数:

MethodDescription
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jasmine-Lily

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值