STL是一个标准规范,它只是为容器、迭代器和泛型算法等组件定义了一整套统一的上层访问接口及各种组件之间搭配运用的一般规则,而没有定义组件底层的具体实现方法。

STL主要包括下面这些组件:I/O流,string类、容器类(Container)、迭代器(Iterator)、存储分配器(Allocator)、适配器(Adapter)、函数对象(Functor)、泛型算法(Algorithm)、数值运算、国际化和本地化支持、以及标准异常类等。

其中最重要的组件是:容器、存储分配器、迭代器、泛型算法、函数对象和适配器,俗称“六大组件”.

一、STL头文件分布

  • 容器类

  • 泛型算法

    只要有一系列元素构成的结构原则上都可以应用泛型算法,像C++/C数组、字符串、I/O流等特殊的容器也可以使用某些泛型算法--它们定义在头文件<algorithm>和<utility>.

  • 迭代器

    迭代器就是用来遍历元素序列或元素集合的“通用指针”,但是每一种容器都定义了合适自己使用的迭代器,那些具有特殊功能的迭代器,如输入/输出迭代器,插入迭代器,反向迭代器等都是迭代器适配器,定义在头文件<iterator>.

  • 数学运算库

  

  • 通用工具

  

  • 其他头文件

二、容器设计原理

  容器对象:容器本身也是C++类的对象,例如std::vector<T> 

  容器元素对象:指容器对象内存储的数据元素,可以是内置类型的对象,也可以是自定义数据类型的对象。

  STL容器的实现方式可以归纳为下图:

  

  STL主要采用向量、链表、二叉树及它们的组合作为底层存储结构来实现容器。

  

  存储方式和访问方式

  向量(vector)和链表是两种最基本的动态结构,也是STL中两种最基本的容器,分别对应动态数组和链表结构,同时它们分别代表了内存中同类型批量数据存放的两种基本方式:连续存储和随机存储。

  由此决定了不同的访问方式:随机访问和顺序访问。

  C++/C的内置数组和vector都是既可以随机访问又可以顺序访问的容器,而list则只能顺序访问。

  vector内存映像如下:

  

  

  list的内存映像

  

  只要底层存储机制采取连续存储方式的容器,就可以随机访问其中任一元素对象,否则只能顺序访问;而任何容器都可以顺序访问,及遍历。

  stack、queue及priority_queue在概念和接口上都不支持随机访问和遍历,这是由它们的语义决定的,而不是由底层存储方式决定的,因此没有迭代器(所以它们才被叫做容器适配器而不是归为容器类)。

  树,在本质上是一种特殊的链表结构,因此只能顺序访问,即从某个节点开始搜索直至到达所要访问的元素对象,或者采用深度优先、广度优先或者前序、中序、后序等方法遍历整颗树,但是不可能直接定位到树上的任一个节点对象。

  

  顺序容器和关联式容器的比较

  这里的“顺序”和“关联”指的是上层接口表现出来的访问方式,并非底层存储方式。

  顺序容器主要采用向量和链表及其组合作为基本存储结构,如堆栈和各种队列。

  关联式容器采用平衡二叉搜索树作为底层存储结构。红黑树是平衡二叉搜索树的一种,其在元素定位上的性能优异(O(log₂N)),STL通常用来实现关联式容器。

  

  链表(list)作为顺序容器的典型代表,其特点就是“天然有序”,即各元素之间具有天然的相对位置关系,这就决定了理论上它可以存储任意多个元素,且不需要对所有元素按值的大小进行排序。

  集合(set)是关联式容器的典型代表,需要从两个层次来理解:概念模型和实现方式。  

  • 概念上是无序的,各个元素没有相对的位置关系,且元素不需要按值的大小排序。
  • 实现上必须是有序的和排序的,只不过要对用户透明(不让用户知道)。
  • 平衡二叉搜索树能够满足这些要求。

  在使用上的区别:

  • 因关联容器无序,所以它只能通过元素的值来定位其中的元素对象,这就是关联式容器具有find()函数的原因,也是调用这种容器的insert()和erase()函数时可以不指定插入位置和删除位置而仅指定元素值或者索引指定原因。(关联容器会自动为新插入的元素安排一个合适的位置)
  • 由于顺序容器本来就有序,所以它是通过元素对象在容器中的位置来标识一个元素的,而不是通过元素的值(因此它可以存储值相等的多个元素对象,而且它们的位置不一定相邻)。这也就是调用顺序容器的insert() 函数 和 erase() 函数时必须指定插入位置和删除位置而不能仅指定元素值 的原因。当然关联式容器也能存储值相等的元素,比如multimap和multiset等,但是它们在容器中的位置肯定是相邻的。 
  • 顺序容器的实现不会像关联式容器那样在增加和删除元素时对其元素进行自动排序,它的概念决定了自动排序对查找(定位)其中任一元素的平均效率没有任何贡献(反而会影响插入和删除的效率),永远是O(N),因为只能顺序访问它。这就是顺序容器没有提供find()函数的原因(string除外).
  • 如果元素查找是经常做的操作,插入和删除反而是很少做的操作,那么就不适合使用顺序容器,而应该使用关联式容器;反之就是用顺序容器。

  

  如何遍历容器?

  从图17-2和17-4看出STL的有效元素的表示范围:

  迭代器last要么指向最后一个有效元素的末尾,要么指向一个空白节点,反正不是指向最后一个有效元素。这就是STL容器的“前闭后开”区间法,即[first,last).

  上图17-5的存储结构可以发现,它与list有些共同之处,例如使用一个空白节点来表示end(),而且begin()指向最左端节点,end()指向开头的空白节点而不是指向最右端节点。这就是说关联式容器采用的是二叉树的“中序遍历”,按照默认升序排列,访问结构是:5,10,15,20,23,25,30.

学习和使用STL的更多相关文章

  1. STL笔记(5)条款49:学习破解有关STL的编译器诊断信息

    STL笔记(5)条款49:学习破解有关STL的编译器诊断信息 条款49:学习破解有关STL的编译器诊断信息 用一个特定的大小定义一个vector是完全合法的, vector<int> v( ...

  2. [C/C++] C/C++延伸学习系列之STL及Boost库概述

    想要彻底搞懂C++是很难的,或许是不太现实的.但是不积硅步,无以至千里,所以抽时间来坚持学习一点,总结一点,多多锻炼几次,相信总有一天我们会变得"了解"C++. 1. C++标准库 ...

  3. 学习笔记:STL

    第一部分:(参考百度百科) 一.STL简介 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.它是由Alexander Stepanov.Me ...

  4. C++ 学习笔记之 STL 队列

    一.  引言 在算法以及数据结构的实现中,很多地方我们都需要队列(遵循FIFO,先进先出原则). 为了使用队列,我们可以自己用数组来实现队列,但自己写太麻烦不说,并且还很容易出错. 好在C++的STL ...

  5. 学习笔记-C++ STL iterator与对指针的理解-20170618

    vector的itrerator支持random access #include<iostream> #include<vector> using namespace std; ...

  6. 从0开始 图论学习 邻接表 STL vector

    邻接表表示 用vector实现 writer:pprp 代码如下: #include <bits/stdc++.h> using namespace std; const int maxn ...

  7. C++ 学习笔记之——STL 库 queue

    1. 队列 queue 队列是一种容器适配器,专门用来满足先进先出的操作,也就是元素在容器的一端插入并从另一端提取. bool empty() const; 返回队列是否为空: size_type s ...

  8. C++ 学习笔记之——STL 库 vector

    vector 是一种顺序容器,可以看作是可以改变大小的数组. 就像数组一样,vector 占用连续的内存地址来存储元素,因此可以像数组一样用偏移量来随机访问,但是它的大小可以动态改变,容器会自动处理内 ...

  9. 我的STL学习之路

    说起STL(标准模板库),相信了解C++的都不会陌生吧^_^.LZ是从大三开始学习C++(ps:不是科班出身),并慢慢接触使用STL的,在学校中使用STL比较多的情况是写数据结构代码,使用STL实现数 ...

随机推荐

  1. Oracle EBS 获取用户挂的职责 请求 请求的类别(RTF还是什么的)

    select fu.user_ID, fu.user_name, fu.start_date, fu.END_DATE, fu.description, fe.last_name, fr.RESPON ...

  2. [翻译] WPAttributedMarkup

    WPAttributedMarkup https://github.com/nigelgrange/WPAttributedMarkup WPAttributedMarkup is a simple ...

  3. November 8th 2016 Week 46th Tuesday

    When he can't, he tries a new way to share a new pair. 当他做不到时,他尝试一种新的方式:分享. To share, your failing e ...

  4. 实践和感悟 - scala向下转型和减少穷举

    工作中的问题总结: 问题一:scala 之向下转型 引言:假如在复杂的业务逻辑中,变量的类型不能确认,只能给个接口类型,这样数据类型推导不会错误,但是后面要使用实现类的类型时,你却发现转不过来了? 对 ...

  5. Log4net 使用之 日期字段格式化

    Log4net 是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介. 之前Log4net的日期字段Data一直采 ...

  6. Oracle从一个用户导出数据到另一个用户

    如果想导入的用户已经存在: 1. 导出用户 expdp user1/pass1 directory=dumpdir dumpfile=user1.dmp 2. 导入用户 impdp user2/pas ...

  7. CSS3新特性2D、3D效果讲解

    希望这篇博客可以对你有所帮助,如果有什么技术上的问题,希望我们可以做进一步的交流,如果你觉得我哪里阐述的不正确或者你有更好的更透彻的理解,也可以联系我,我在这里随时等着你. 对于css/html是每个 ...

  8. HDU 5550 - Game Rooms(DP + 前缀和预处理)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5550 题意: 一个大楼有n(2≤n≤4000)层,每层可以建一个乒乓球房或者一个游泳房,且每种房间在大楼 ...

  9. PHP类的静态(static)方法和静态(static)变量使用介绍

    PHP类的静态(static)方法和静态(static)变量使用介绍,学习php的朋友可以看下     在php中,访问类的方法/变量有两种方法: 1. 创建对象$object = new Class ...

  10. 8 个不常见但很有用的 Git 命令

    1. 拉取远程代码并且覆盖本地更改 2. 列出远程和本地所有分支 3. 强制更新远程分支 4. 回滚一个 merge 5. 修改之前的提交记录或者很久前提交的记录 6. 使用多个远程代码库,并且使用多 ...