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 返回指向容器末尾位置的反向迭代器
#########################################################################################
例题

潜伏者

最新文章

  1. linux的用户与用户组
  2. Hive介绍、安装(转)
  3. vmware vcenter appliance dhcp 改为 静态IP导致web service认证失败
  4. QT对话框设计
  5. Thread类详解
  6. Objective-C 【多个对象内存管理(野指针&amp;内存泄漏)】
  7. 【打包成exe安装包文件发布你的程序】使用QT联系人管理系统的例子
  8. yarn资源管理器高可用性的实现
  9. [AngularJS] angular-md-table for Angular material design
  10. ac命令根据/var/log/wtmp文件登录退出时间计算用户连接时间
  11. asp.net 导出excel文件
  12. html5 canvas的教程
  13. xlrd的使用详细介绍以及基于Excel数据参数化实例详解
  14. 【Android】用Cubism 2制作自己的Live2D——官方App样例源码学习(1)!
  15. DOS 命令 os系统(windows)
  16. 网易云音乐 歌词制作软件 BesLyric (最新版本下载)
  17. hdu 1217 汇率 Floyd
  18. jar包读取jar包内部和外部的配置文件,springboot读取外部配置文件的方法
  19. socket的同步异步的性能差别,以及listen的参数backlog
  20. HTTP错误 404.17–Not Found 请求的内容似乎是脚本,因而将无法有静态文件处理程序来处理

热门文章

  1. unity目前学的一些操作
  2. ASP.NET MVC自定义Numberic属性的验证信息
  3. ASP.NET Identity系列教程-3【运用ASP.NET Identity】
  4. ubuntu set up 7 - power
  5. Beamer加入背景图片
  6. A Bug&#39;s Life____并查集
  7. multiprocessing 方法解析:
  8. 2018ICPC南京站Problem J. Prime Game
  9. &lt;input type=&quot;file&quot;&gt;文件上传
  10. Devxtreme 显示Master-Detail数据列表, 数据显示颜色