zoukankan      html  css  js  c++  java
  • STL六大组件之——容器知识大扫盲

    STL中的容器主要涉及顺序容器类型:vector、list、deque,顺序容器适配器类型:stack、queue、priority_queue。标准库中的容器分为顺序容器和关联容器。顺序容器(sequential container)内的元素按其位置存储和访问,顾名思义,这些内部元素是顺序存放的;顺序容器内的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定。而关联容器的元素按键(key)排序。

          容器类共享部分公共接口。标准库定义的三种顺序容器类型:vector、list、deque,它们的差别仅在访问元素的方式,以及添加或删除元素相关操作的代价。顺序容器适配器包括:stack、queue和priority_queue。容器只定义了少量操作,大多数操作由算法库提供。如果两个容器提供了相同的操作,则它们的接口(函数名和参数个数)应该相同。 

    标准容器类

    说明

    顺序性容器

    vector

    从后面快速的插入与删除,直接访问任何元素

    deque

    从前面或后面快速的插入与删除,直接访问任何元素

    list

    双链表,从任何地方快速插入与删除

    关联容器

    set

    快速查找,不允许重复值

    multiset

    快速查找,允许重复值

    map

    一对多映射,基于关键字快速查找,不允许重复值

    multimap

    一对多映射,基于关键字快速查找,允许重复值

    容器类型:

     vector

     容器,支持快速随机访问(连续存储) 

     list

     链表,支持快速插入/删除

     deque

     双端队列,支持随机访问(连续存储),两端能快速插入和删除

     stack

     栈

     queue

     队列

     priority_queue

     优先级队列

    下表为迭代器为所有容器类型所提供的运算:

     *iter

     返回类型iter所指向的元素的引用 

     iter->mem

     对iter进行解引用,并取得指定成员

     ++iter

     给iter加1,使其指向容器中下一个元素

     iter++

     

     --iter

     给iter减1,使其指向容器中前一个元素

     iter--

     

     iter1 == iter2

     当两个迭代器指向同一个容器中的同一元素,或者当它们都指向

     iter1 != iter2

     同一个容器的超出末端的下一个位置时,两个迭代器相等。

    vector和deque容器的迭代器提供了额外的运算:迭代器的算术运算和另一些关系运算,如下表所示:

     iter + n

     在迭代器上加(减)整数值,将产生指向容器中前面(后面)第n个元素的迭代器;

     iter - n

     新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一位置。

     iter1 += iter2

     复合运算:先加(减),再赋值

     iter1 -= iter2

     

     iter1 - iter2

     只适用于vector和deque

     >, >=, <, <=

     比较迭代器的位置关系;只适用于vector和deque

    关系操作符只适用于vector和deque容器,这是因为只有这两种容器为其元素提供快速、随机的访问。它们确保可根据元素位置直接有效地访问指定的容器元素。这两种容器都支持通过元素位置实现的随机访问,因此它们的迭代器可以有效地实现算术和关系运算。

    迭代器范围:[first, last)是一个左闭合区间,表示范围从first开始,到last结束,但不包括last。注意:如果first不等于last,则对first反复做自增运算必须能够到达last;否则,即last位于first之前,则将发生未定义行为。

       迭代器范围使用左闭合的意义:因为这样可以统一表示空集,就无需特别处理。

       另外,使用迭代器时,要特别留意迭代器的可能的失效问题。

    访问元素:

     back()

     返回容器的最后一个元素的引用。如果容器为空,则该操作未定义

     front()

     返回容器的第一个元素的引用。如果容器为空,则该操作未定义

     c[n]

     返回下标为n的元素的引用;如果n<0 or n>=size(),则该操作未定义
       (注:只适用于vector和deque容器)

     at[n]

     返回下标为n的元素的引用;如果下标无效,则抛出异常out_of_range异常
       (注:只适用于vector和deque容器)

    删除元素 :  

     erase(p)

     删除迭代器p所指向的元素。返回一个迭代器,它指向被删除的元素后面的元素。如果p指向容器内最后一个元素,则返回的迭代器指向容器的超出末端的下一个位置;如果p本身就是指向超出末端的下一个位置的迭代器,则该函数未定义

     erase(b, e)

     删除[b, e)内的所有元素。返回一个迭代器,它指向被删除元素段后面的元素。如果e本身就是指向超出末端的下一个位置的迭代器,则返回的迭代器也指向超出末端的下一个位置。

     clear()

     删除容器内的所有元素,返回void

     pop_back()

     删除容器内的最后一个元素,返回void。如果容器为空,则该操作未定义。

     pop_front()

     删除容器内的第一个元素,返回void。如果c为空容器,则该操作未定义
       (注:只适用于list和deque容器)

    赋值与swap: 

     c1 = c2

     删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型必须相同。

     c1.swap(c2)

     交换内容:调用该函数后,c1中存放的是c2原来的元素,c2中存放的是c1原来的元素。c1和c2的类型必须相同。该函数的执行速度通常要比将c2的元素复制到c1的操作快。

     c.assign(b, e)

     重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。

     c.assign(n, t)

     将容器c重新设置为存储n个值为t的元素。

    注意:assign操作首先删除容器内所有的元素,再将参数所指定的新元素插入到容器中。

         swap操作不会删除或插入任何元素,而且保证在常量时间内实现交换。由于容器内没有移动任何元素,因此迭代器不会失效。但要注意这些迭代器指向了另一个容器中的元素。

    容器的选用:

    vector和deque容器提供了对元素的快速访问,但付出的代价是,在容器的任意位置插入或删除元素,比在容器尾部插入和删除的开销更大,因为要保证其连续存储,需要移动元素;list类型在任何位置都能快速插入和删除,因为不需要保证连续存储,但付出的代价是元素的随机访问开销较大。特征如下:

       1)与vector容器一样,在deque容器的中间insert或erase元素效率比较低;

       2)不同于vector容器,deque容器提供高效地在其首部实现insert和erase的操作,就像在尾部一样;

       3)与vector容器一样而不同于list容器的是,deque容器支持对所有元素的随机访问。

       4)在deque容器首部或尾部删除元素则只会使指向被删除元素的迭代器失效。在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器都失效。

     容器的比较:

    vector (连续的空间存储,可以使用[]操作符)快速的访问随机的元素,快速的在末尾插入元素,但是在序列中间岁间的插入,删除元素要慢,而且如果一开始分配的空间不够的话,有一个重新分配更大空间,然后拷贝的性能开销。
    deque (小片的连续,小片间用链表相连,实际上内部有一个map的指针,因为知道类型,所以还是可以使用[],只是速度没有vector快)快速的访问随机的元素,快速的在开始和末尾插入元素,随机的插入,删除元素要慢,空间的重新分配要比vector快,重新分配空间后,原有的元素不需要拷贝。对deque的排序操作,可将deque先复制到vector,排序后在复制回deque。
    list (每个元素间用链表相连)访问随机元素不如vector快,随机的插入元素比vector快,对每个元素分配空间,所以不存在空间不够,重新分配的情况。
    set:内部元素唯一,用一棵平衡树结构来存储,因此遍历的时候就排序了,查找也比较快的哦。
    map :一对一的映射的结合,key不能重复。

    stack :适配器,必须结合其他的容器使用,stl中默认的内部容器是deque。先进后出,只有一个出口,不允许遍历。
    queue: 是受限制的deque,内部容器一般使用list较简单。先进先出,不允许遍历。
    vector<bool> 与bitset<> ,前面的可以动态改变长度。
    priority_queue: 插入的元素就有优先级顺序,top出来的就是优先级最高的了
    valarray 专门进行数值计算的,增加特殊的数学函数。

       一些容器选用法则:

       1)如果程序要求随机访问元素,则应使用vectordeque容器;

       2)如果程序必须在容器的中间位置插入或删除元素,则应采用list容器;

       3)如果程序不是在容器的中间位置,而是在容器首部或尾部插入或删除元素,则应采用deque容器;

       4)如果只需要在读取输入时在容器的中间位置插入元素,然后需要随机访问元素,则可以在输入时将元素读入到一个list容器中,然后对容器排序,再将排序后的list容器复制到vector容器中。

       5)如果程序既需要随机访问,又需要在容器的中间位置插入或删除元素,此时应当权衡哪种操作的影响较大,从而决定选择list容器还是vector或deque容器。注:此时若选择使用vector或deque容器,可以考虑只使用它们和list容器所共有的操作,比如使用迭代器而不是下标,避免随机访问元素等,这样在必要时,可以很方便地将程序改写为使用list容器。

  • 相关阅读:
    Python学习心得第二周-作业
    Python学习心得第二周-02 字符串、列表、元组、字典
    Python学习心得第二周-01 数字类型
    eclipse 性能调优之内存分配
    Spring 面试
    技巧 linux 如何显示一个文件的某几行(中间几行)
    命令 scp
    机器学习遇到的好的资料
    maven 使用记录
    “冷启动”问题浅析
  • 原文地址:https://www.cnblogs.com/geekpaul/p/4157702.html
Copyright © 2011-2022 走看看