• 【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,则u是vector对象)

    表达式返回值描述时间复杂性
    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,则u是vector对象),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& x)将列表x与调用列表合并。前提是两个列表已排序。生成的排序列表位于调用列表中,x留空。此函数具有线性时间复杂性。
    void remove(const T & val)从列表中删除所有的val。此函数具有线性时间复杂性。
    void sort()使用<运算符对列表进行排序;对于N个元素,时间复杂度为NlogN。有成员方法sort()的原因是list不支持随机访问,因此不能使用非成员方法sort()
    void splice(iterator pos, list 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 A; // a set of string objects 4.有一个模板可选参数用于指定排序时使用的比较函数,默认是less<>(旧版本的C++没有默认值,需要自己指定) set > 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模板> var; 4.pair template class将keyValue和Value联合到一起,可以使用下面的方法添加元素 pair item(213, "Los Angeles"); multimap.insert(item); codes.insert(pair (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::iterator,multimap::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,则u是vector对象)
        表达式         返回值         描述                                              时间复杂性
        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,则u是vector对象)
                    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& x)               将列表x与调用列表合并。前提是两个列表已排序。生成的排序列表位于调用列表中,x留空。此函数具有线性时间复杂性。
                void remove(const T & val)                  从列表中删除所有的val。此函数具有线性时间复杂性。
                void sort()                                 使用<运算符对列表进行排序;对于N个元素,时间复杂度为NlogN
                                                            有成员方法sort()的原因是list不支持随机访问,因此不能使用非成员方法sort()
                void splice(iterator pos, list 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 A; // a set of string objects
                4.有一个模板可选参数用于指定排序时使用的比较函数,默认是less<>(旧版本的C++没有默认值,需要自己指定)
                    set > 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模板> var;
                4.pair template class将keyValue和Value联合到一起,可以使用下面的方法添加元素
                    pair item(213, "Los Angeles");
                    multimap.insert(item);
                    codes.insert(pair (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::iterator,multimap::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 
    #include 
    #include 
    #include 
    #include
    #include
    #include
    typedef int KeyType;
    typedef std::pair Pair;
    typedef std::multimap MapCode;
    void outint(int n) { std::cout << n << " "; }
    int main()
    {
        using namespace std;
        cout << "sequence********************************************************************" << endl;
        list one(5, 2); // list of 5 2s
        int stuff[5] = { 1,2,4,8, 6 };
        list two;
        two.insert(two.begin(), stuff, stuff + 5);
        int more[6] = { 6, 4, 2, 4, 6, 5 };
        list 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 A(s1, s1 + N);
        set B(s2, s2 + N);
        ostream_iterator 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 C;
        cout << "Set C:\n";
        set_union(A.begin(), A.end(), B.begin(), B.end(),
            insert_iterator >(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 D;
        set_intersection(A.begin(), A.end(), B.begin(), B.end(),
            insert_iterator >(D, D.begin()));
        copy(D.begin(), D.end(), out);//for
        cout << endl;
        cout << "Set E:\n";
        set E;
        set_difference(A.begin(), A.end(), B.begin(), B.end(),
            insert_iterator >(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 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。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
  • 相关阅读:
    jmeter性能测试,各个指标的预估/测试出来/计算出来,各种关系
    网工证书选择,就业岗位等相关说明
    C# BackgroundWorker用法详解(源码可直接使用)
    使用域名转发mqtt协议,避坑指南
    Django实战项目-学习任务系统-用户注册
    计算机毕业设计之java+springboot基于vue的网上书城管理系统
    利用索引机制进行绕过
    基于springboot小区物业管理系统
    平均风向风速计算(单位矢量法)
    【Zabbix监控一】zabbix的原理与安装
  • 原文地址:https://blog.csdn.net/weixin_44410704/article/details/128035461