美文网首页
STL学习笔记

STL学习笔记

作者: 再想想1991 | 来源:发表于2016-08-22 21:12 被阅读0次

    STL(Standard Template Library)里有很多组成部分,但是主要有三个,容器、迭代器和算法

    容器用来管理某个特定对象的集合。每一种容器都有自己的优点和缺点,在项目中根据不同的需求,使用不同的容器。容器可以是数组、链表或者类字典。

    迭代器用于遍历对象集合的元素。这些集合可以是容器或容器的子集。每一个容器类都提供了它自己的迭代器类型。

    算法用来处理的元素的集合。例如,可以进行搜索、排序等操作。

    STL的数据和操作是分离的。数据存储在容器里,使用算法进行操作。迭代器是这两者之间的粘合剂,让算法与容器可以进行交互。

    某种程度上,STL的概念与面向对象编程的原则相背,

    STL数据和算法是分离的而不是结合。STL是泛型编程的一个很好的例子。容器和算法分别是任意类型和类的泛型。STL提供了更通用的组件。还可以通过使用适配器和仿函数来达到特殊要求。

    容器

    容器管理着一系列元素,为了满足不同的需求,STL提供了多种类型的容器,见下图。

    主要可以分为三大类

    序列容器是有序集合,其中的每个元素都有特定位置。这个位置取决于插入的时间和地点,但是它跟元素的值无关。STL包含5个预定义的序列容器类:array、vector、deque、list和forward_list。

    关联容器是把元素的值按照某种规则排好顺序的集合。STL包含4个预定义的关联容器类:set、multiset、map和multimap。

    无序(关联)容器是无序集合。主要关注一个元素是否在集合中。不论是插入的顺序还是插入元素的值对元素的位置都没有任何影响。STL包含4个预定义的无序容器类:unordered_set、unordered_multiset、unordered_map和unordered_multimap。

    序列容器通常是数组或链表的实现

    关联容器通常是二叉树的实现

    无序容器通常是哈希表的实现

    容器适配器

    容器适配器提供顺序容器的特殊接口

    stack 堆栈适配器(LIFO)

    queue 改写容器来提供队列(FIFO数据结构)

    priority_queue 改写容器来提供优先级队列

    迭代器

    根据迭代器所支持的操作,一般分为下面5种。

    前向迭代器只能利用递增运算符进行前向迭代。像unordered_set、unordered_multiset、unordered_map和unordered_multimap这些容器都“至少”是用前向迭代器(某些情况下可以提供双向迭代器)。

    双向迭代器是可以用递增运算符向前迭代,或者用递减运算符向后迭代。像list、set、multiset、map和multimap的迭代器都是双向迭代器。

    随机访问迭代器具有双向迭代器的所有属性。此外,他们还可以进行随机访问。这种迭代器本身支持运算操作,可以改变偏移量,也可以利用关系运算符(< 和 >)比较迭代器。像vector、deque、array和string的迭代器都是这类迭代器。

    输入迭代器能够在迭代时读取或处理一些值。如Input stream iterators。

    输出迭代器能够在迭代时输出一些值。如Inserters、和output stream iterators。

    算法

    STL提供了一些标准算法来处理集合元素。这些算法一般提供最基本的功能,如搜索、排序、复制、修改和数值处理。

    算法不是容器类的成员函数,而是全局函数。算法可以操作不同容器类型的元素,甚至可以操作用户自定义的容器类型。总之,既减少了代码量,又增强了性能。

    迭代器适配器

    任何操作起来像迭代器的东西都可以当作迭代器。所以可以写出像迭代器的一些类但又执行不一样的操作。C++标准库提供的一些预定义的特殊迭代器,即迭代器适配器。

    一般分为四类:

    Insert iterators也称为inserters,用来将“赋值新值”操作转换为“安插新值”操作。通过这种迭代器,算法可以执行安插(insert)行为而非覆盖(overwrite)行为。所有Insert迭代器都隶属于Output迭代器类型,所以它只提供赋值(assign)新值的能力。通常算法会将数值赋值给目的迭代器,如copy()算法

    Stream iterators是一种迭代器配接器,可以把stream当成算法的原点和终点。更明确的说,一个istream迭代器可以用来从input stream中读元素,而一个ostream迭代器可以用来对output stream写入元素。Stream迭代器的一种特殊形式是所谓的stream缓冲区迭代器,用来对stream缓冲区进行直接读取和写入操作。

    Reverse iterators重新定义递增运算和递减运算,使其行为正好倒置。

    Move iterators很像一个底层迭代器(必须至少有一个InputIterator)。如果这个迭代器被当作输入迭代器来用,要注意的是,值的操作是移动而不是复制。

    重点介绍向量:

    向量容器使用动态数组存储、管理对象。因为数组是一个随机访问数据结构,所以可以随机访问向量中的元素。在数组中间或是开始处插入一个元素是费时的,特别是在数组非常大的时候更是如此。然而在数组末端插入元素却很快。

    实现向量容器的类名是vector(容器是类模板)。包含vector类的头文件名是vector。所以,如果要在程序里使用向量容器,就要在程序中包含下面语句:

    #include

    此外,在定义向量类型对象时,必须指定该对象的类型,因为vector类是一个类模板。例如,语句:

    vector intList;

    将intList声明为一个元素类型为int的向量容器对象。类似地,语句:

    vector stringList;将stringList声明为一个元素类型为string的向量容器对象。

    声明向量对象

    vector类包含了多个构造函数,其中包括默认构造函数。因此,可以通过多种方式来声明和初始化向量容器。表一描述了怎样声明和初始化指定类型的向量容器。

    表一     各种声明和初始向量容器的方法

    语句作用

    vector vecList;创建一个没有任何元素的空向量vecList(使用默认构造函数)

    vector vecList(otherVecList)创建一个向量vecList,并使用向量otherVecList中的元素初始化该向量。向量vecList与向量otherVecList的类型相同

    vector vecLIst(size);

    创建一个大小为size的向量vecList,并使用默认构造函数初始化该向量

    vector vecList(n,elem);创建一个大小为n的向量vecList,该向量中所有的n个元素都初始化为elem

    vector vecList(begin,end);创建一个向量vecList,并初始化该向量(begin,end)中的元素。即,从begin到end-1之间的所有元素

    在介绍了如何声明向量顺序容器之后,让我们开始讨论如何操作向量容器中的数据。首先,必须要知道下面几种基本操作:

    元素插入

    元素删除

    遍历向量容器中的元素

    假设vecList是一个向量类型容器。表二给出了在vecList中插入元素和删除元素的操作,这些操作是vector类的成员函数。表二还说明了如何使用这些操作。

    表二     向量容器上的各种操作

    语句作用

    vecList.clear()从容器中删除所有元素

    vecList.erase(position)删除由position指定的位置上的元素

    vecList.erase(beg,end)删除从beg到end-1之间的所有元素

    vecList.insert(position, elem)将elem的一个拷贝插入到由position指定的位置上,并返回新元素的位置

    vecList.inser(position, n, elem)将elem的n个拷贝插入到由 position指定的位置上

    vecList.insert(position, beg, end)将从beg到end-1之间的所有元素的拷贝插入到vecList中由position指定的位置上

    vecList.push_back(elem)将elem的一个拷贝插入致List的末尾

    vecList.pop_back()删除最后元素

    vecList.resize(num)将元素个数改为num。如果size()增加,默认的构造函数负责创建这些新元素

    vecList.resize(num, elem)将元素个数改为num。如果size()增加,默认的构造函数将这些新元素初始化为elem

    在向量容器中声明迭代器

    vector类包含了一个typedef iterator,这是一个public成员。通过iterator,可以声明向量容器中的迭代器。例如,语句:

    vector::iterator intVeciter;        将intVecIter声明为int类型的向量容器迭代器。

    因为iterator是一个定义在vector类中的typedef,所以必须使用容器名(vector)、容器元素类型和作用域符来使用iterator。

    表达式:

    ++intVecIter

    将迭代器intVecIter加1,使其指向容器中的下一个元素。表达式:*intVecIter

    返回当前迭代器位置上的元素。

    注意,迭代器上的这些操作和指针上的相应操作是相同的。运算符*作为单目运算符使用时,称为递引用运算符。

    下面将讨论如何使用迭代器来操作向量容器中的数据。假设有下面语句:

    vector intList;

    vector::iterator intVecIter;

    第一行中的语句将intList声明为元素为int类型的向量容器。第二行中的语句将intVecIter声明为元素为int类型的向量容器的迭代器。

    容器与函数begin和end

    所有容器都包含成员函数begin和end。函数begin返回容器中第一个元素的位置;函数end返回容器中最后一个元素的位置。这两个函数都没有参数。在执行下面语句:

    intVecIter = intList.begin();

    迭代器intVecIter指向容器intList中第一个元素。

    下面的for循环将intList中所有元素输出互标准输出设备上:

    for (intVecIter = intList.begin(); intVecIter != intList.end();

    cout<<*intVecList<<"     ";

    可以通过表三中给出的操作直接访问向量容器中的元素。

    表三 访问向量容器中元素的操作

    表达式作用

    vecList.at(index)返回由index指定的位置上的元素

    vecList[index]返回由index指定的位置上的元素

    vecList.front()返回第一个元素 (不检查容器是否为空)

    vecList.back()返回最后一个元素(不检查容器是否为空)

    表三说明:可以按照数组的方式来处理向量中的元素(注意,在C++中,数组下标从0始。,向量容器中第一个元素的位置也是0)。

    徽号类中还包含:返回容器中当前元素个数的成员函数,返回可以插入到容器中的元素的最大个数的成员函数等。表四描述其中 一些操作(假设vecCont是向量容器)。

    表四 计算向量容器大小的操作

    表达式作用

    vecCont.capacity()返回不重新分配空间可以插入到容器vecCont中的元素的最大个数

    vecCont.empty()容器vecCont为空,返回true;否则,返回false

    vecCont.size()返回容器vecCont中当前的个数

    vecCont.max_size()返回可以插入到容器vecCont中的元素的最大个数

    相关文章

      网友评论

          本文标题:STL学习笔记

          本文链接:https://www.haomeiwen.com/subject/hyegsttx.html