STL学习笔记(一)

1. 容器(Containers)

容器分为两类:前端

  1. 序列式容器(Sequence containers),此乃可序群集,其中每一个元素均有固定位置————取决于插入时机和地点,和元素值无关。STL提供三个定义好的序列式容器:vector,deque,list
  2. 关联式容器(Associative containers),此乃已序群集,元素位置取决于特定的排序准则,即元素位置取决于元素值,和插入次序无关。STL提供四个关联式容器:set,multiset,map,multimap

1.1 序列式容器

  • Vector Vector将其元素置于一个dynamic array中加以管理,容许随机存取,便可以利用索引直接存取任何一个元素。 在array尾部附加或移除元素很是快速,但在array中部或头部安插元素比较费时算法

  • Deque Deque与Vector同样,也是一个dynamic array,能够向两端发展,所以不论在尾部或头部安插元素都十分迅速,但在中间部分安插元素则比较费时express

  • List 1. List由双向链表实做而成。 2. List不提供随机存取,即List并无提供以operator[]直接存取元素的能力。 3. List的优点是:在任何位置上执行安插或删除动做都很是迅速。数组

  • 序列式容器中,向容器首部或末端添加元素分别使用push_front和push_back函数,但vector中并未提供push_front函数数据结构

1.2 关联式容器

关联式容器依据特定的排序准则,自动为其元素排序。排序准则以函数形式呈现,用来比较元素值(value)或元素键(key)。缺省状况下以operator<进行比较,也能够提供本身的比较函数,定义不一样的排序准则。dom

  • Set Set的内部元素按其值自动排序,每一个元素只能出现一次。
  • Multiset Multiset和Set相同,只不过它容许元素重复。
  • Map Map的元素都是“实值/键值”所造成的一个对组,每一个元素都有一个键,是排序准则的基础。每个键只能出现一次,不容许重复。Map可被视为关联式数组。
  • Multimap Multimap和Map相同,但容许元素重复,即Multimap可包含多个键值相同的元素。Multimap可被当作“字典”
  • **全部关联式容器都有一个可供选择的template参数,指明排序准则。缺省采用operator<。

2. 容器适配器(Container Adapter)

除了上述容器类别,为知足特殊需求,STL提供了一些特别的并预先定义好的容器适配器,包括:数据结构和算法

  • Stack Stack容器对元素采起LIFO管理策略。
  • Queue Queue容器对元素采起FIFO管理策略。
  • Priority Queue Priority Queue容器中的元素能够拥有不一样的优先级。

3. 迭代器

迭代器是一个“可遍历STL容器内所有或部分元素”的对象。一个迭代器用来指出容器中的一个特定位置。其基本操做以下:函数

  • operator* 返回当前位置上的元素值。若是该元素拥有成员,你能够透过迭代器,直接以operator->取用它们。
  • operator++、operator-- 将迭代器前进或后退一个元素
  • operator==、operator!= 判断两个迭代器是否指向同一位置。
  • operator= 为迭代器赋值。

3.1 全部容器类别都提供一些成员函数,使咱们能够得到迭代器####

  • begin() 返回指向容器起始点的迭代器。
  • end() 返回一个指向容器结束点的迭代器。结束点在最后一个元素以后,这样的迭代器称为“逾尾”迭代器。
  • rbegin() 返回一个指向最后一个元素的逆向迭代器
  • rend() 返回一个指向第一个元素前一个位置的逆向迭代器。

3.2 任何一种容器都定义有两种迭代器性别:

  1. container::iterator 这种迭代器以“读写”模式遍历元素。
  2. Container::const_iterator 这种迭代器以“只读”模式遍历元素。

3.3 迭代器分类

迭代器被划分为5类。STL预先定义好的全部容器中,其迭代器均属于一下两种类型:指针

  1. 双向迭代器(Bidirectional iterator) 双向迭代器能够双向行进:以++或--运算前进或后退。**list、set、multiset、map和multimap这些容器所提供的迭代器都属于此类。
  2. 随机存取迭代器(Random access iterator) 随机存取迭代器不但具有双向迭代器的全部属性,还具有随机访问能力。更明确的说,他们提供了“迭代器算术运算”必要的操做符(和“通常指针的算术运算符”彻底对应)。你能够对迭代器增长或减小一个偏移量、处理迭代器之间的距离、或是使用<和>之类的retational(相对关系)操做符来比较两个迭代器。vector、deque和string所提供的迭代器都属于此类。

为了撰写尽量与容器型别无关的范型程序代码,最好不要使用随机存取迭代器的特有操做。以下例,能够在任何容器上运做:code

for (pos = col.begin();pos != col.end();++pos)
{
	...
}

而下面的程序代码就不是全部容器都使用了:

for (pos = col.begin();pos < col.end();++pos)
{
	...
}

由于只有random access iterator才支持operator<。

3.4 迭代器适配器

迭代器是一个纯粹抽象的概念:任何东西,只要其行为相似迭代器,它就是一个迭代器。所以,能够撰写一些类别,具有迭代器接口,但有着各不相同的行为。STL提供了数个预先定义的特殊适配器,即迭代器适配器:

  • Insert iterator(安插型迭代器) 安插型迭代器能够解决算法的“目标空间不足”问题。
  1. Back inserter:内部调用push_back(),在容器尾端插入元素(追加)。
copy (col1.begin(),col1.end(),back_inserter(col2));

固然,只有在提供push_back()成员函数的容器中,back inserter才能派上用场。 2. Front inserter:内部调用push_front(),将元素安插于容器最前端。

copy (col1.begin(),col1.end(),front_inserter(col2));

只有在提供push_front()成员函数的容器中,front inserter才能派上用场,在STL中,这样的容器是deque和list。 3. General inserter:通常性的inserter,它的做用是将元素插入“初始化时接受之第二参数”所指定位置的前方,其内部调用insert()成员函数。全部STL容器都提供有insert()成员函数 |算是(expression)|Insert种类| |-|-| |back_inserter(container)|使用push_back()在容器尾端安插元素,元素排列次序和安插次序相同| |front_inserter(container)|使用push_front()在容器前段安插元素,元素排列次序和安插次序相反| |Insert(container,pos)|使用insert()在pos位置上安插元素,元素排列次序和安插次序相同|

  • Stream interator(流迭代器)
  1. istream_iterator<string>(cin) 产生一个可从“标准输入流cin”中读取数据的stream iterator。元素经过通常的operator>>被读取进来
  2. istream_iterator<string>() 调用istream iterator的default构造函数,产生一个表明“流结束符号”的迭代器。
  3. ostream_iterator<string>(cout,"\n") 产生一个output stream iterator,经过operator<<向cout写入数据,第二个参数(可由可无)被用来做为元素之间的分隔符。
  • Reverse iterator(逆向迭代器) 全部容器均可以经过rbegin()和rend()成员函数产生reverse iterator。

4. 算法(Algorithm)

算法并不是容器类别的成员函数,而是一种搭配迭代器使用的全局函数。

  • 优点:全部算法只需实做一份,就能够对全部容器运做,数据与操做被明确划分开来,透过特定的接口彼此互动。
  • 劣势:用法有失直观;某些数据结构和算法之间并不兼容,或者即便兼容也会致使糟糕的效能)。

4.1 区间

  • 全部算法都用来处理一个或多个区间内的元素。
  • 全部算法处理的都是半开区间————包含起始元素位置但不包含结尾元素位置。 [begin,end]

4.2 一些简单的算法

  1. min_element()、max+element() 调用他们时,必须传入两个参数,定义出欲处理的元素范围。
  2. sort() 将由两个参数设定出来的区间内的全部元素加以排序。还能够出入一个排序准则,缺省的是operator<。
  3. find() 在给定范围内搜寻某个值,若成功返回目标元素,若失败,范围一个“逾尾迭代器”,亦即find()所接受的第二个参数。
  4. reverse() 将区间内的元素反转。
  5. distance() 返回两个迭代器之间的距离

4.3 处理多个区间

一些算法能够同时处理多个区间,一般必须设定第一个区间的起点和终点,至于其它区间,你只需设定起点便可,终点一般可由第一区间的元素数量推导出来。下面例子中,equal()从头开始逐一比较col1和col2的全部元素:

if (equal (col1.begin(),col1.end(),col2.begin()))
{
	...
}

所以,col2中参与比较的元素数量,简洁取决于col1内的元素数量。 因此,若是某个算法用来处理多个区间,那么当你调用它时,务必确保第二区间所拥有的元素个数,至少和第一区间内的元素个数相同。 固然,若是目标区间空间不足,可使用安插型迭代器

4.4 更易型算法(Manipulating algorithm)

更易型算法是指会“删除或重排或修改元素”的算法。

  1. 移除元素(remove) 算法remove()删除指定区间中的某一元素。
remove (col1.begin(),col1.end(),3);

但remove()算法并无真正删除某一元素所占的空间,只是将以后的元素向前移动覆盖了某一数值。事实上,remove返回了一个新的终点,利用这个新的终点,经过容器所提供的成员函数,能够完全删除一个元素。

col1.erase(remove(col1.begin(),col1.end(),3),col1.end());

为什么算法不本身直接调用erase()?这就是STL为了获取灵活性而付出的代价。经过“以迭代器为接口”,STL将数据结构和算法分离开来。迭代器只是“容器中某一位置”的抽象概念而已,通常来讲,迭代器对本身所属的容器一无所知,任何“以迭代器访问容器元素”的算法,都不得经过迭代器调用容器类别所提供的任何成员函数。

相关文章
相关标签/搜索