9.1 简介

  • 容器库是类模板与算法的汇集,允许程序员简单地访问常见数据结构,例如队列、链表和栈。
  • 有三类容器——顺序容器、关联容器和无序关联容器——每种都被设计为支持不同组的操作。
    1. 顺序容器:顺序容器实现能按顺序访问的数据结构。

      • vector :向量,动态的连续数组
      • deque双端队列
      • list :双链表
      • stack :栈,适配一个容器以提供栈(LIFO 数据结构)
      • queue :队列,适配一个容器以提供队列(FIFO 数据结构)
      • priority_queue :优先队列,适配一个容器以提供优先级队列
    2. 关联容器:关联容器实现能快速查找(O(log n)复杂度)的数据结构。
      • set :集合,唯一键的集合,按照键排序
      • multiset :键的集合,按照键排序
      • map :键值对的集合,按照键排序,键是唯一的
      • multimap :键值对的集合,按照键排序
    3. 无序关联容器
  • 容器管理为其元素分配的存储空间,并提供直接或间接地通过迭代器(拥有类似指针属性的对象)访问它们的函数。
  • 大多数容器拥有至少几个常见的成员函数,并共享功能。特定应用的最佳容器不仅依赖于提供的功能,还依赖于对于不同工作量的效率。

9.2 顺序容器

9.2.1 vector

原型template < class T, class Alloc = allocator<T> > class vector;
  1. 包含在 #include<vector> 库中
  2. 是封装动态数组的顺序容器。
  3. 元素在内存上是连续的,所以支持下标读取
  4. 可以存储基本类型和构造类型数据
  5. 存储是自动管理的,按需扩张收缩。 vector 通常占用多于静态数组的空间,因为要分配更多内存以管理将来的增长。
  6. 可以根据存储需要调整容器容量的大小(一般按2倍扩容)
  7. 扩容时会重新分配内存,需要把已存储数据拷贝到新内存
  • vector 上的常见操作复杂度如下:

    • 随机访问——常数 O(1)
    • 在末尾插入或移除元素——均摊常数 O(1)
    • 插入或移除元素——与到 vector 结尾的距离成线性 O(n)

成员函数

  1. at()

    • 函数原型:reference at (size_type pos);

    • 返回位于指定位置 pos 的元素的引用有边界检查

    • pos 不在容器范围内,则抛出 std::out_of_range类型的异常。

      eg:

      for(int i=0;i<10;++i)
      a.push_back(i);//vector容器a从尾端加入0~9
      for(int i=0;i<10;++i){//如果超出范围会报"out_of_range"错误
      a.at(i)+=10;//因为是引用,所以修改后原始值发生变化
      printf("%d ",a.at(i));
      }
  2. operator[]

    • 函数原型:reference operator[]( size_type pos );

    • 返回位于指定位置 pos 的元素的引用不进行边界检查

      eg:

      for(int i=0;i<10;++i)
      a.push_back(i);//vector容器a从尾端加入0~9
      for(int i=0;i<=10;++i){//如果超出范围不会报错
      a[i]+=10;//因为是引用,所以修改后原始值发生变化
      printf("%d ",a[i]);
      }
  3. front()

    • 函数原型:reference front();
    • 返回到容器首元素引用
    • 空容器上对 front 的调用是未定义的。
  4. back()

    • 函数原型:reference back();
    • 返回到容器中最后一个元素的引用
    • 空容器上对 back 的调用是未定义的。
  5. iterator :迭代器

    • 迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器上遍访的接口,设计人员无需关心容器的内容。

    • 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素。

    • 每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象

    • 迭代器提供一些基本操作符:*、++、==、!=、=

    • 迭代器按照定义方式分成以下四种。

      1. 正向迭代器,定义方法如下:

        • 容器类名::iterator 迭代器名;
      2. 常量正向迭代器,定义方法如下:
        • 容器类名::const_iterator 迭代器名;
      3. 反向迭代器,定义方法如下:
        • 容器类名::reverse_iterator 迭代器名;
      4. 常量反向迭代器,定义方法如下:
        • 容器类名::const_reverse_iterator 迭代器名;

      eg:

      • 迭代器都可以进行 ++ 操作。反向迭代器和正向迭代器的区别在于:

        • 对正向迭代器进行++操作时,迭代器会指向容器中的后一个元素;
        • 而对反向迭代器进行++操作时,迭代器会指向容器中的前一个元素。
      std::vector<int> v;  //v是存放int类型变量的可变长数组,开始时没有元素
      for (int i = 0; i<5; ++i)
      v.push_back(i); //push_back成员函数在vector容器尾部添加一个元素
      std::vector<int>::iterator it; //定义正向迭代器
      for (it = v.begin(); it != v.end(); ++it) { //用迭代器遍历容器
      printf("%d ",*it);//*it 就是迭代器it指向的元素
      *it *= 2; //每个元素变为原来的2倍
      }
      std::vector<int>::reverse_iterator it;//定义反向迭代器
      for ( it = v.rbegin(); it != v.rend(); ++it)
      printf("%d ",*it);
  6. begin()

    • 函数原型:iterator begin();
    • 返回指向容器首元素的迭代器。
    • 若容器为,有可能是未定义行为。
  7. end()

    • 函数原型:iterator end();
    • 返回指向容器末元素后一元素迭代器
    • 此元素表现为占位符,试图访问它会导致未定义行为。
  8. rbegin()

    • 函数原型:reverse_iterator rbegin();
    • 返回指向逆向容器首元素的逆向迭代器。它对应非逆向容器的末元素。
  9. rend()

    • 函数原型:reverse_iterator rend();
    • 返回指向逆向容器末元素后一元素的逆向迭代器。
    • 它对应非逆向容器首元素的前一元素。此元素表现为占位符,试图访问它导致未定义行为
  10. empty()

    • 函数原型:bool empty() const;
    • 检查容器是否无元素,即是否 begin() == end()
  11. size()

  • 函数原型:size_type size() const;

    • 返回容器中的元素数,即std::distance(begin(), end())
  1. reserve()
  • 函数原型:void reserve( size_type new_cap );

    • 增加 vector 的容量到大于或等于 new_cap 的值。若 new_cap 大于当前的 capacity() ,则分配新存储,否则该方法不做任何事。
    • reserve() 不更改 vectorsize
    • new_cap 大于 capacity(),则所有迭代器,包含尾后迭代器和所有到元素的引用都被非法化。否则,没有迭代器或引用被非法化。
    • 不能用 reserve() 减少容器容量。
    • 正确使用 reserve() 能避免不必要的分配,但不适当地使用 reserve() 可能会实际增加重分配的数量
  1. capacity()
  • 函数原型:size_type capacity() const;

    • 返回容器当前已为之分配空间的元素数。
  1. clear()
  • 函数原型:void clear();

    • 从容器擦除所有元素。此调用后 size() 返回零。
    • 非法化任何指代所含元素的引用、指针或迭代器。任何尾后迭代器亦被非法化。
    • 保持 vectorcapacity() 不变
  1. insert()
  • 函数原型:

    1. iterator insert( iterator pos, const T& value );

      - 在 pos 前插入 value

      2. void insert( iterator pos, size_type count, const T& value );

      - 在 pos 前插入 valuecount 个副本。

      3. void insert( iterator pos, InputIt first, InputIt last);

      - 在 pos 前插入来自范围 [first, last) 的元素。
  1. erase()
  • 函数原型:

    1. iterator erase( iterator pos ); //移除位于 pos 的元素。

    2. iterator erase( iterator first, iterator last );//移除范围 [first; last) 中的元素。

    • 擦除点或之后的迭代器,包含 end() 迭代器将失效。
    • 迭代器 pos 必须合法且可解引用。从而不能以 end() 迭代器(合法,但不可解引用)为 pos 的值。
    • first==last 则迭代器 first 不必可解引用:擦除空范围是无操作。
    • 返回值:后随最后被移除元素的迭代器。若迭代器 pos 指代最后元素,则返回 end() 迭代器。
  1. push_back()
  • 函数原型:void push_back( const T& value );

    - 在容器末尾添加新的元素 value

    - 如果当前size()大于容器capacity(),则重新分配内存。

    - 如果当前size()大于容器capacity(),则所有迭代器和引用都被非法化。

    - 如果没有重新分配,仅在插入点前的迭代器和引用保持合法。尾后迭代器亦被非法化。
  1. pop_back()
  • 函数原型:void pop_back();

    - 移除容器的最末元素。

    - 在空容器上调用 pop_back 是未定义的
  1. resize()
  • 函数原型:void resize (size_type count, value_type val = value_type());

    - 重新调整容器大小为 count

    - 如果 count 小于等于容器size ,则只调整size

9.3 关联容器

9.3.1 map

  map 容器是关联容器的一种。在关联容器中,对象的位置取决于和它关联的键的值。键可以是基本类型,也可以是类类型。关联容器是与非关联容器(顺序容器)相对应的,顺序容器中元素的位置不依赖于元素的值,而是和该元素加入容器时的位置有关。关联容器的类型有下面八种:

按关键字有序保存元素
map //关联数组;保存关键字-值对
set //关键字即值,只保存关键字的容器
multimap //关键字可以重复出现的map
multiset //关键字可以重复出现的set 无序关联容器
unordered_map //用哈希函数组织的map,无序
unordered_set //用哈希函数组织的set,无序
unordered_multimap //哈希组织的map;关键字可以重复
unordered_multiset //哈希组织的set,关键字可以重复

  map 容器有四种,每一种都是由类模板定义的。所有类型的 map 容器保存的都是键值对的元素。map 容器的元素是 pair<const K, T> 类型的对象,这种对象封装了一个 T 类型的对象和一个与其关联的 K 类型的键。pair 元素中的键是 const,因为修改键会扰乱容器中元素的顺序。每种 map 容器的模板都有不同的特性:

1、map 容器:map 的底层是由红黑树实现的,红黑树的每一个结点都代表着 map 的一个元素。该数据结构具有自动排序的功能,因此 map 内部的元素都是有序的,元素在容器中的顺序是通过比较键值确定的。默认使用 less<K> 对象比较。

2、multimap 容器:与map容器类似,区别只在于multimap容器可以保存键值相同的元素。

3、unordered_map容器:该容器的底层是由哈希(又名散列)函数组织实现的。元素的顺序并不是由键值决定的,而是由键值的哈希值确定的,哈希值是由哈希函数生成的一个整数。利用哈希函数,将关键字的哈希值都放在一个桶(bucket)里面,具有相同哈希值的放到同一个桶。unordered_map内部元素的存储是无序的,也不允许有重复键值的元素,相当于java中的HashMap

4、unordered_multimap容器:也可以通过键值生成的哈希值来确定对象的位置,但是它允许有重复的元素。

mapmultimap容器的模板都定义在map头文件中,unordered_mapunordered_multimap容器的模板都定义在unordered_map头文件中中。

  • multi前缀表明键值不必唯一,但是如果没有这个前缀,键值必须唯一。
  • unordered前缀表明容器中元素的位置是通过其键值所产生的哈希值来决定的,而不是通过比较键值决定的,即容器中的元素是无序的。如果没有这个前缀,则容器中元素是由比较键值决定的,即有序。

  下图展示了一个用名称作为键值 map<K, T>容器,对象是整数,用来表示年龄。

  前面讲过map容器的底层是由红黑树(一种非严格意义上的平衡二叉树)实现的,元素检索的时间复杂度是O(logN),相比于顺序检索的线性时间复杂度还是很快的。

定义和初始化

  map类模板有四个类型参数,但是一般只需要指定前两个模板参数的值。第一个是键值的类型,第二个是所保存对象的类型。我们通常所用的一种构造一个map对象的方法是:

map<string, int> mapStudent;

  当初始化一个map时,必须提供关键字类型和值类型。我们将每个关键字-值对包围在花括号中: {key,value} 来指出它们一起构成了map中的一个元素。初始化列表有两种方式:

map<string, string> authors = { {"Joyce", "James"},
{"Austen", "Jane"},
{"Dickens", "Charles"} };

或者:

map<string, int> authors { {"Joyce", "James"}, {"Austen", "Jane"}, {"Dickens", "Charles"}};

但是需要注意的是:初始化列表的方式是C++11的新特性,对版本比较早的编译器不支持这一特性。

成员函数

下面列出几个常用的成员函数:

  1. size 返回有效元素个数

  2. max_size 返回容器支持的最大元素个数

  3. empty 判断容器是否为空,为空是返回true,否则返回false

  4. clear 清空map容器

  5. insert 插入数据

  6. erase 删除元素

  7. 9.1 简介

    容器库是类模板与算法的汇集,允许程序员简单地访问常见数据结构,例如队列、链表和栈。

    有三类容器——顺序容器、关联容器和无序关联容器——每种都被设计为支持不同组的操作。

    顺序容器:顺序容器实现能按顺序访问的数据结构。

    vector :向量,动态的连续数组

    deque :双端队列

    list :双链表

    scount 查找某键值是否存在,若存在,返回1;不存在返回0

  8. find 查找某键值是否存在,若存在返回指向元素的迭代器指针,不存在返回end()

数据的访问和遍历
map访问和查找元素的常用方法有:
=========================================================================================
operator[] 访问元素,也可以用于修改某个元素的value值;不进行下标(关键字)是否存在的检查(即如果关键字不存在,程序运行不会出错),访问到某个元素时,
如果该元素的键值不存在则直接创建该元素,返回是初始的值(比如int型的初始为0,则返回0,string初始为NULL,则返回NULL)
at 访问元素,也可以用于修改某个元素的value值;会进行下标(关键字)是否存在的检查,如果关键字不存在,则会拋出 out_of_range 异常。
========================================================================================= 利用迭代器访问元素
*****************************************************************************************
map<K, T>::iterator it;
(*it).first; // the key value (of type Key)
(*it).second; // the mapped value (of type T)
(*it); // the "element value" (of type pair<const Key,T>)
元素的键值和value值分别是迭代器的first和second属性。也可以用迭代器指针直接访问。
it->first; // same as (*it).first (the key value)
it->second; // same as (*it).second (the mapped value)
***************************************************************************************** 迭代器的成员函数:
begin    返回指向容器起始位置的迭代器(iterator)
end    返回指向容器末尾位置的迭代器
rbegin 返回指向容器起始位置的反向迭代器(reverse_iterator)
rend 返回指向容器末尾位置的反向迭代器
#########################################################################################
例题

潜伏者

九、c++容器的更多相关文章

  1. 四:(之九_容器资源限制)Dockerfile语法梳理和实践

    9 容器资源限制 9.1 Virtualbox :工具操作 9.2 内存限制 docker --help  只限定memory bytes,则memory-swap默认与其存储相同. 资源限制生效: ...

  2. openshift 容器云从入门到崩溃之九《容器监控-报警》

    容器状态监控 主要是监控POD的状态包括重启.不健康等等这些k8s api 状态本身会报出来,在配合zabbix报警 导入zabbix模板关联上oc master主机 <?xml version ...

  3. Spring源码分析(十九)容器的功能扩展概览

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 经过前面几章的分析,相信大家已经对 Spring 中的容器功能有了简单 ...

  4. Docker 与 K8S学习笔记(九)—— 容器间通信

    容器之间可通过IP.Docker DNS Server或joined三种方式进行通信,今天我们来详细学习一下. 一.IP通信 IP通信很简单,前一篇中已经有所涉及了,只要容器使用相同网络,那么就可以使 ...

  5. 侯捷STL学习(九)--关联式容器(Rb_tree,set,map)

    layout: post title: 侯捷STL学习(九) date: 2017-07-21 tag: 侯捷STL --- 第十九节 容器rb_tree Red-Black tree是自平衡二叉搜索 ...

  6. Docker-compose 多个Docker容器管理:以MYSQL和Wordpress为例

    搬砖的陈大师版权所有,转载请注明:http://www.lenggirl.com/tool/docker-compose.html Docker-compose 多个Docker容器管理:以MYSQL ...

  7. Qt容器组件(二)之QWidgetStack、QMdiArea、QDockWidget

    QT中有九种容器组件,分别是组合框QGroupBox.滚动区QScrollArea.工具箱QToolBox.选项卡QTabWidget.控件栈QWidgetStack.框架QFrame.组件QWidg ...

  8. Qt容器组件(一)之QGroupBox、QScrollArea、QToolBox、QTabWidget

    QT中有九种容器组件,分别是组合框QGroupBox.滚动区QScrollArea.工具箱QToolBox.选项卡QTabWidget.控件栈QWidgetStack.框架QFrame.组件QWidg ...

  9. Docker实践之04-操作容器

    目录 一.查看容器列表 二.启动容器 三.终止容器 四.重启容器 五.后台运行容器 六.获取容器输出信息 七.进入容器 八.导出和导入容器 九.删除容器 一.查看容器列表 可以使用命令docker c ...

  10. Docker容器化技术(上)

    目录 Docker容器化技术 一.介绍 二.Docker的发展 三.Docker安装 四.阿里云Docker镜像加速 五.Docker的基本概念 六.命令 七.Docker宿主机与容器通信 八.容器内 ...

随机推荐

  1. PHP版常用算法

    PHP版常用算法最近准备面试的资料,顺便整理一下以前的基本算法,写个DEMO记录一下 //冒泡//逐行对比,满足条件则交换function bubbleSort($arrData,$sort = 'd ...

  2. C# VS2017 WinForm 打包和升级

    C# WinFrom打包不怎么常用,但一年总有那么一两次,每次都记不全,为了方便自己回看,于是有了本篇文章. 本例使用<C#工具类LogHelper>的解决方案作为例子,实现WinForm ...

  3. SVN提交更新文件,抛出"svn: No such revision 27106"异常问题处理

    SVN,不管是更新或者是提交原来存在的文件,都会抛出此异常"svn: No such revision 27106",注意,是原来存在的文件,要是新增的文件,不会出现此问题. 百度 ...

  4. 如何将博客搬至CSDN

    简单聊下对于博客园的印象是技术改变世界,作为一个IT技术人员很乐意把这里当作自己的网上家园,每天在这里分享着精彩的原创内容,看重的不是华丽的外表.诱人的虚名,而是纯净.专注.对技术人员的理解. CSD ...

  5. SurfaceView 与view区别详解

    SurfaceView 与view区别详解 https://blog.csdn.net/u011339364/article/details/83347109 2018年10月24日 17:20:08 ...

  6. laravle中常见的数据库加密

    // 1.md5加密 $str=md5('123456'); // 2.base64_decode加密 $str2=base64_encode('123456'); // 2.1 base64_解密 ...

  7. Python3标准库:enum枚举

    1. enum枚举 枚举是一组符号名称(枚举成员)的集合,枚举成员应该是唯一的.不可变的.在枚举中,可以对成员进行恒等比较,并且枚举本身是可迭代的. 1.1 创建枚举 可以使用class语法派生Enu ...

  8. 841. 字符串哈希(hash)

    给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2l1,r1,l2,r2,请你判断[l1,r1l1,r1]和[l2,r2l2,r2]这两个区间所包含的字符串子串是否完 ...

  9. VS的使用技巧记录:

    调试: F5:调试运行 会在编译前进行debug F10:单步步过   遇到函数不会进入函数内部执行 F11:单步步入   遇到函数会进入函数一步一步执行 ctrl+F5:直接运行不调试

  10. gulp-sass设置不同样式风格的输出方法

    sass最终输出的样式包括下面几种样式风格:嵌套输出方式 nested展开输出方式 expanded 紧凑输出方式 compact 压缩输出方式 compressed sass: nav { ul { ...