C++学习笔记(22)——STL标准模板库

1前言

本篇笔记开始总结C++标准中的一系列强大的库。STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISOC++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。

STL是Alex Stepov和Meng Lee于1994年在Hewlett-Packard(惠普)实验室开发发布。从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming),引入了诸多新的名词,比如像需求(requirements),概念(concept),模型(model),容器(container),算法(algorithmn),迭代子(iterator)等。与OOP(object-oriented programming)中的多态(polymorphism)一样,泛型也是一种软件的复用技术。

从内容层次来看,它的设计基石是模板技术,该库包含了13个头文件,分别为:algorithm,deque,functional,iterator,list,map,memory,numeric,queue,set,stack,utility,vector。这些头文件中涉及了基于模板技术的、具有泛型思想的四大组件:

•    迭代器 (iterator)

•    容器 (container)

•    函数对象(function object)

•    算法函数 (algorithm)

关于STL的信息很多,无法在短时间内用简短的篇幅把其功能和用法全部总结,本篇笔记旨在熟悉一个框架并了解泛型编程的思想,增加一些感性认识。更详细的内容可以参考开发者Alex Stepov和Meng Lee以及P.J.Plauger撰写的C++ STL一书,且有中文版(中国电力出版社)。

2迭代器

2.1迭代器基本概念

理解迭代器是理解STL的关键所在。模板使得算法独立于数据类型,二迭代器使得算法独立于使用的容器类型。泛型编程旨在用一个函数来处理数组、链表或任何其他容器类型。模板提供了存储在容器中的数据类型的通用表示,因此还需要遍历容器中的值的通用表示,迭代器则完成这项工作。

迭代器在STL中起着粘合剂的作用,它将算法和容器联系起来,主要用来存取容器中的元素。几乎所有的算法都是通过迭代器存取元素进行工作的。每一个容器也都定义了其本身所专有的迭代器,用以存取容器中的元素。

我们首先来分析一下迭代器应该如何工作?

首先,迭代器应该能都执行解除引用操作,这样才能访问容器中的值。即p为迭代器,则应具有*p访问容器内值的定义。

其次,迭代器应该可以执行p++或++p的操作,这显而易见。

再有,迭代器应该可以进行==和!=判断。

最后,迭代器可以进行赋值,如p=q。

基本的迭代器拥有以上定义就够了,我们不难发现常规指针就可以完成上述操作。但实际上,STL迭代器可以完成的操作远不止于上述功能。其实我们在使用迭代器时,无须知道迭代器是怎么实现的。下面是一个简单的例子:

   vector<double> v;        // 定义一个vector容器

   v.push_back(5.5);        // 向容器中添加个元素

   v.push_back(6.6);

   v.push_back(7.7);



   // 遍历向量的元素

   vector<double>::iterator b = v.begin(); // 指向容器的第一个元素

   vector<double>::iterator e = v.end(); // 指向容器尾元素的下一个位置



   // C++11新标准的写法, auto关键字为类型推断,由编译器自动完成

   // auto b = v.begin();

   // auto e = v.end();



   for (vector<double>::iterator iter = b; iter != e; ++iter)

   {

      cout << *iter << endl;

   }

我们只需要知道:

迭代器最常用到的就是begin和end成员。其中begin成员负责返回指向第一个元素。end成员则负责返回指向容器的“ 尾元素的下一个位置(one past the end) ”。要特别注意end成员不是指向尾元素,而是指向尾元素的下一个位置,被称为超尾位置。同时要注意迭代器范围(iterator range) 由一对迭代器表示,最常见的就是begin和end。begin和end所表示的范围恰好是容器的全部元素。这是一个左闭合区间(left-inclusive interval),其标准的数学表达式为:

[begin,end)(左闭右开)

初始化语句:vector<double>::iterator iter = b; 如果你的环境支撑C++11标准,那么强烈建议你写成auto iter = b; 即使用类型自动推断关键字auto。使用auto使程序更为简洁,也不会出错,由编译器自动推断。

条件判断语句处建议用== 和 != 运算符,因为并非所有的容器都重载了 < > 运算符,但所有的容器都重载了== 和 != 运算符。所以我们应该习惯使用 == 和 != 运算符。

2.2 迭代器分类

STL根据不同的需求定义了5种迭代器,并根据所需的迭代器类型对算法进行了描述。

•    输入迭代器 : 只读,不写。单遍扫描,只能递增。

•    输出迭代器 : 只写,不读。单遍扫描,只能递增。

•    前向迭代器 : 可读可写。多遍扫描,只能递增。

•    双向迭代器 : 可读可写。多遍扫描,可递增递减。

•    随机访问迭代器 : 可读可写。多遍扫描,支持全部迭代器运算。

这些迭代器都可以执行解除引用操作,也可以进行比较(==和!=运算符)。下面逐一分析其特有的属性。

2.2.1 输入迭代器

术语“输入”是从程序的角度说的,也即来自容器的信息。所以,输入迭代器可被用来读取容器中的信息。具体说可以用*iterator来读取容器中的值,但不能修改值。注意,输入迭代器是单向迭代器,可以递增,但不可以倒退,即只可以++iterator,不可以--iterator。另外,输入迭代器只支持一遍算法,同一个输入迭代器不能两遍遍历一个序列。

2.2.2 输出迭代器

STL使用术语“输出”来指用于将信息从程序传输给容器的迭代器。因此,输入迭代器可以通过解除引用来让程序修改其值,但不能读取。这就像程序发送到显示器上的信息,cout可以修改发送到显示器上的字符流,但却不能读取屏幕上的内容。同时,输出迭代器也只可以递增,不可递减。简而言之,对于单通行、只读算法,可以使用输入迭代器,而对于单通行、只写算法,则可以使用输出迭代器。

2.2.3正向迭代器

与输入输出迭代器相似,正向迭代器只使用++来遍历容器。但它总是按相同的顺利遍历一系列值,这使得它支持多次遍历同行的算法。

2.2.4双向迭代器

双向迭代器具有正向迭代器的所有特性,并支持递减运算符。

2.2.5随机访问迭代器

有些算法比如二分检索和标准排序要求能够直接跳到容器的任何一个元素,这就是随机访问。随机访问迭代器具有双向迭代器的所有特性,同时增加了支持随机访问的操作。即支持iterator+n的运算形式。

注意,各种迭代器的类型并不是确定的,只是一种概念性描述。它的分类功能是相对于容器说的,比如对于vector,它的迭代器则是随机访问迭代器,二对于list(双向链表),它的迭代器则是双向迭代器。

3容器

3.1 容器的基本概念

容器的定义是:特定类型对象的集合。

在没有使用容器之前,我们可能会用数组解决一些问题。使用数组解决问题,那么我们必须要知道或者估算出大约要存储多少个对象,这样我们会创建能够容纳这些对象的内存空间大小。当我们要处理一些完全不知道要存储多少对象的问题时,数组显的力不从心。我们可以使用容器来解决这个问题。容器具有很高的可扩展性,我们不需要预先告诉它要存储多少对象,只要创建一个容器,并合理的调用它所提供的方法,所有的处理细节由容器自身完成。

新标准库的容器的性能几乎肯定与最精心优化过的同类数据结构一样好(通常会更好)。现代C++程序应该使用标准容器库,而不是更原始的数据结构,如内置数组。STL中的容器大致可以分为3类15种,下面将具体介绍每一种容器。

3.2 序列容器

序列容器是一种元素之间有顺序的线性表,是一种线性结构的可序群集。这和我们数据结构课程上所讲的线性表是一样的。序列容器中的每个元素位置是固定的,除非你使用了插入或者删除操作改变了这个位置。序列容器不会根据元素的特点排序而是直接保存了元素操作时的逻辑顺序。比如我们一次性对一个顺序容器追加三个元素,这三个元素在容器中的相对位置和追加时的逻辑次序是一致的。

STL中包括7中序列容器,分别为:deque,forward_list(C++11),list,queue,priority_queue,stack和vector。他们都支持insert,erase和clear操作。其中某些容器可能还支持front, back, at,push_front, push_back以及数组下标访问的操作。

•    vector : 可变大小数组,支持快速随机访问。在尾部之外的位置插入或者删除元素可能很慢。

•    deque : 双端队列。支持快速随机访问。在头尾位置插入、删除速度很快。

•    list : 双向链表。list不支持数组表示法和随机访问,只支持双向顺序访问。在list中任何位置进行插入、删除操作速度都很快。

•    forward_list : 单向链表。只支持单向顺序访问。在链表的任何位置进行插入、删除操作都很快。(C++11标准新加)

•    queue : 是一个适配器类,不仅不允许随机访问队列元素,甚至不允许遍历队列。他把使用限制在定义队列的基本操作上,可以将元素添加到队尾(push)、从队首删除元素(pop),查看队首队尾值(front和back),查看元素数目(size)和测试队列是否为空(empty)。

• priority_queue:另一个适配器类。它支持的操作与queue相同。区别在于最大的元素被移到队首。

• stack:也是适配器类。他给底层类提供了典型的栈接口。操作限制为push,pop,top,size和empty。

这里考虑到形式上的相似性,我们姑且将array和string也作为序列:

•    array : 固定大小数组。支持快速随机访问。不能添加或者删除元素。(C++11标准新加)

•    string : 与vector相似的容器,但专门用于保存字符。随机访问快,在尾部插入删除快。

如何选择呢?根据自己的编程需求选择适合的容器。vector、deque和list这三者我们可以优先考虑vector。vector容器适用于大量读写,而插入、删除比较少的操作。list容器适用于少量读写,大量插入,删除的情况。deque折中了vector和deque, 如果你需要随机存取又关心数据的插入和删除,那么可以选择deque。forward_list适用于符合它这种逻辑结构的情况,array一般用来代替原生的数组。string用于和字符串操作有关的一些情况,也是实际开发中应用最多的。

3.3 关联容器

关联容器(associative-container)和顺序容器有着根本的不同。序列容器中的元素是按他们在容器中的位置来顺序保存和访问的。而关联容器将值与键关联在一起,用键来查找值。关联容器的有点在于,它提供了对元素的快速访问。关联容器也允许插入新元素,但不能指定元素的插入位置。关联容器通常是使用某种树实现的。树是一种数据结构,类似于链表,节点的添加和删除比较简单,但相对于链表,树的查找速度更快。

STL中提供了4中关联容器。分别为set, multiset, map, multimap。

set/ multiset: set是最简单的关联容器,其值与键相同,即只保存键的容器。键是唯一的,可翻转,可排序。内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,内部由二叉树实现(实际上基于红黑树(RB-tree)实现),便于查找。与序列容器一样,set也是用模板参数来指定要存储的值类型。set提供了一个将迭代区间作为参数的构造函数:  

 string s[6] = {"This", "test", "is", "a","This"};

   set<string> A(s, s+6);

   ostream_iterator<string, char> out(cout, " ");

   copy(A.begin(), A.end(), out);

其中“6”指向超尾元素。由于键的唯一性,最后的结果中将只有一个“this”,且集合最终被排序:

“This a is test”

set容器默认为集合排序,默认参数是less,即升序排序。另外,set容器还继承了set_union(求并集),set_intersection(求交集),set_difference(求差集)。insert(插入元素,因为set会默认排序,因此不能指定插入的位置,只接受插入的键),lower_bound(将键作为参数返回第一个不小于键值的迭代器),upper_bound(将键作为参数返回第一个大于键值的迭代器)。multiset是键可重复的set。

map/ multimap: 关联数组;map的元素是成对的键值/实值,键与值类型不同,但键是唯一的。内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次。为了实现这种 “成对”的数据结构,STL还引入了pair类型,一种辅助的数据结构。使用关联容器,绕不开pair类型。它定义在标准库头文件utility中。一个pair保存两个数据成员。类似容器,pair是一个用来生成特定类型的模板。当创建pair时,我们必须提供两个类型名,pair的成员将具有对应的类型。与其他标准库类型不同,pair的数据成员是public的。两个成员分别命名为first和second。multimap是键可重复的map。常见的用法如下:   

pair<const int, string> item(010, "Beijing");

map<int, string> cities;

cities.insert(item);

for (map<int, string>::iterator it = cities.begin(); it != cities.end(); ++it)

{

   cout<<it->first<<" "<<it->second<<endl;

}

另外,count(键值)函数接受键作为参数,返回具有该键的元素数目。lower_bound和upper_bound函数与set功能相同。

3.4 无序关联容器(C++11)

无序关联容器与关联容器一样,也将值与键关联起来,并使用键来查找值。但底层的差别在于,关联容器是基于树结构的,而无序关联容器是基于数据结构哈希表的。这旨在提高添加和删除元素的速度以提高查找算法的效率。有4种无序关联容器:

•    unordered_map : 用哈希函数组织的map

•    unordered_set : 用哈希函数组织的set

•    unordered_multimap : 哈希组织的map;关键字可以重复出现

•    unordered_multiset : 哈希组织的set;关键字可以重复出现

4函数对象

很多STL算法都是用函数对象,也叫函数符(functor)。函数符是可以以函数方式和( )结合使用的任意对象。这包括函数名,指向函数的指针和重载了( )运算符的类对象。所以通常来说,函数对象是某个类的实例,行为和函数一致。

提供函数对象的作用是为了支持将函数作为参数的STL函数。如sort函数:sort(v.begin(), v.end(), less())或sort(v.begin(), v.end(), greator()),实际上这里的less和greator是STL中的两个模板类,为了方便作为诸如sort函数的参数,重载了()运算符,进而成为了函数对象。

一些常见的运算符都有相应的函数符预定义:

运算符

函数符

+

plus

-

minus

*

multiplies

/

divides

%

modulus

-

negate

==

equal_to

!=

not_equal_to

>

greater

<

less

>=

greater_equal

<=

less_equal

&&

logical_and

||

logical_or

!

logical_not

5算法

虽然容器提供了众多操作,但有些常见的操作,比如查找特定的元素,替换或者删除某个特定值,重新排序等,这些由一组泛型算法(generic algorithm)来实现。STL包含很多处理容器的非成员函数,比如sort,copy,find等。大多数的算法都定义在头文件algorithm中,有些关于数值的泛型算法定义在numeric这个头文件中。

5.1 算法形式

标准库提供了上百个算法,幸运地是,它们的算法结构基本上是一致的。这样我们就不用死记硬背了。他们都是用迭代器来标识要处理的数据区间和结果的放置位置。首先,他们都使用模板来提供泛型;其次他们都使用迭代器来提供访问容器中数据的通用表示。

大多数的算法具有如下4种形式之一:

alg(beg, end, other args);

alg(beg, end, dest, other args);

alg(beg, end, beg2, other args);

alg(beg, end, beg2, end2, other args);

其中alg是算法的名字,beg和end表示算法所操作的输入范围。dest表示指定目的位置,beg2和end2表示接受第二个范围。

标准算法库对迭代器而不是容器进行操作。因此,算法不能直接添加或者删除元素(可以调用容器本身的操作来完成)。

如find算法:

    int val2 = 100;

    // 没有找到这个值,返回vec.cend()

    auto res = find(vec.begin(), vec.end(), val2);

    if (res == vec.cend())

    {

        cout << "没找到元素!" << endl;

    }

    else

    {

        cout << *res << endl;

    }

1.   访问序列中的元素

2.   比较此元素与我们要查找的值

3.   如果此元素与我们要查找的值匹配,find返回标示此元素的值。

4.   否则,find前进到下一个元素,重复执行步骤2和3。

5.   如果到达序列尾,find停止。

6.   如果find到达序列末尾,它应该返回一个指出元素未找到的值。此值和步骤3中返回的值必须具有相同的类型。

5.2 算法分类

STL中算法大致分为四类:

1)、非修改式序列算法:指不直接修改其所操作的容器内容的算法。

2)、修改式序列算法:指可以修改它们所操作的容器内容的算法。

3)、排序算法:包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作。

4)、数值算法:对容器内容进行数值计算。

5.3查找算法

查找算法共13个,通常用来判断容器中是否包含某个值

adjacent_find: 在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的ForwardIterator。否则返回last。重载版本使用输入的二元操作符代替相等的判断。

binary_search: 在有序序列中查找value,找到返回true。重载的版本实用指定的比较函数对象或函数指针来判断相等。

count: 利用等于操作符,把标志范围内的元素与输入值比较,返回相等元素个数。

count_if: 利用输入的操作符,对标志范围内的元素进行操作,返回结果为true的个数。

equal_range: 功能类似equal,返回一对iterator,第一个表示lower_bound,第二个表示upper_bound。

find: 利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的一个InputIterator。

find_end: 在指定范围内查找"由输入的另外一对iterator标志的第二个序列"的最后一次出现。找到则返回最后一对的第一个ForwardIterator,否则返回输入的"另外一对"的第一个ForwardIterator。重载版本使用用户输入的操作符代替等于操作。

find_first_of: 在指定范围内查找"由输入的另外一对iterator标志的第二个序列"中任意一个元素的第一次出现。重载版本中使用了用户自定义操作符。

find_if: 使用输入的函数代替等于操作符执行find。

lower_bound: 返回一个ForwardIterator,指向在有序序列范围内的可以插入指定值而不破坏容器顺序的第一个位置。重载函数使用自定义比较操作。

upper_bound: 返回一个ForwardIterator,指向在有序序列范围内插入value而不破坏容器顺序的最后一个位置,该位置标志一个大于value的值。重载函数使用自定义比较操作。

search: 给出两个范围,返回一个ForwardIterator,查找成功指向第一个范围内第一次出现子序列(第二个范围)的位置,查找失败指向last1。重载版本使用自定义的比较操作。

search_n: 在指定范围内查找val出现n次的子序列。重载版本使用自定义的比较操作。

5.4 排序算法

排序和相关算法共有14个,提供元素排序策略。

inplace_merge: 合并两个有序序列,结果序列覆盖两端范围。重载版本使用输入的操作进行排序。

merge: 合并两个有序序列,存放到另一个序列。重载版本使用自定义的比较。

nth_element: 将范围内的序列重新排序,使所有小于第n个元素的元素都出现在它前面,而大于它的都出现在后面。重载版本使用自定义的比较操作。

partial_sort: 对序列做部分排序,被排序元素个数正好可以被放到范围内。重载版本使用自定义的比较操作。

partial_sort_copy: 与partial_sort类似,不过将经过排序的序列复制到另一个容器。

partition: 对指定范围内元素重新排序,使用输入的函数,把结果为true的元素放在结果为false的元素之前。

random_shuffle: 对指定范围内的元素随机调整次序。重载版本输入一个随机数产生操作。

reverse: 将指定范围内元素重新反序排序。

reverse_copy: 与reverse类似,不过将结果写入另一个容器。

rotate: 将指定范围内元素移到容器末尾,由middle指向的元素成为容器第一个元素。

rotate_copy: 与rotate类似,不过将结果写入另一个容器。

sort: 以升序重新排列指定范围内的元素。重载版本使用自定义的比较操作。

stable_sort: 与sort类似,不过保留相等元素之间的顺序关系。

stable_partition: 与partition类似,不过不保证保留容器中的相对顺序。

5.5 删除和替换算法

删除和替换算法共15个。

copy: 复制序列

copy_backward: 与copy相同,不过元素是以相反顺序被拷贝。

iter_swap: 交换两个ForwardIterator的值。

remove: 删除指定范围内所有等于指定元素的元素。注意,该函数不是真正删除函数。内置函数不适合使用remove和remove_if函数。

remove_copy: 将所有不匹配元素复制到一个制定容器,返回OutputIterator指向被拷贝的末元素的下一个位置。

remove_if: 删除指定范围内输入操作结果为true的所有元素。

remove_copy_if: 将所有不匹配元素拷贝到一个指定容器。

replace: 将指定范围内所有等于vold的元素都用vnew代替。

replace_copy: 与replace类似,不过将结果写入另一个容器。

replace_if: 将指定范围内所有操作结果为true的元素用新值代替。

replace_copy_if: 与replace_if,不过将结果写入另一个容器。

swap: 交换存储在两个对象中的值。

swap_range: 将指定范围内的元素与另一个序列元素值进行交换。

unique: 清除序列中重复元素,和remove类似,它也不能真正删除元素。重载版本使用自定义比较操作。

unique_copy: 与unique类似,不过把结果输出到另一个容器。

5.6 排列组合算法

排列组合算法有2个,提供计算给定集合按一定顺序的所有可能排列组合

next_permutation: 取出当前范围内的排列,并重新排序为下一个排列。重载版本使用自定义的比较操作。

prev_permutation: 取出指定范围内的序列并将它重新排序为上一个序列。如果不存在上一个序列则返回false。重载版本使用自定义的比较操作。

5.7 算术算法

算术算法有4个。

accumulate: iterator对标识的序列段元素之和,加到一个由val指定的初始值上。重载版本不再做加法,而是传进来的二元操作符被应用到元素上。

partial_sum: 创建一个新序列,其中每个元素值代表指定范围内该位置前所有元素之和。重载版本使用自定义操作代替加法。

inner_product: 对两个序列做内积(对应元素相乘,再求和)并将内积加到一个输入的初始值上。重载版本使用用户定义的操作。

adjacent_difference: 创建一个新序列,新序列中每个新值代表当前元素与上一个元素的差。重载版本用指定二元操作计算相邻元素的差。

5.8 生成和异变算法

生成和异变算法有6个。

fill: 将输入值赋给标志范围内的所有元素。

fill_n: 将输入值赋给first到first+n范围内的所有元素。

for_each: 用指定函数依次对指定范围内所有元素进行迭代访问,返回所指定的函数类型。该函数不得修改序列中的元素。

generate: 连续调用输入的函数来填充指定的范围。

generate_n: 与generate函数类似,填充从指定iterator开始的n个元素。

transform: 将输入的操作作用与指定范围内的每个元素,并产生一个新的序列。重载版本将操作作用在一对元素上,另外一个元素来自输入的另外一个序列。结果输出到指定容器。

5.9关系算法

关系算法有8个。

equal: 如果两个序列在标志范围内元素都相等,返回true。重载版本使用输入的操作符代替默认的等于操作符。

includes: 判断第一个指定范围内的所有元素是否都被第二个范围包含,使用底层元素的<操作符,成功返回true。重载版本使用用户输入的函数。

lexicographical_compare: 比较两个序列。重载版本使用用户自定义比较操作。

max: 返回两个元素中较大一个。重载版本使用自定义比较操作。

max_element: 返回一个ForwardIterator,指出序列中最大的元素。重载版本使用自定义比较操作。

min: 返回两个元素中较小一个。重载版本使用自定义比较操作。

min_element: 返回一个ForwardIterator,指出序列中最小的元素。重载版本使用自定义比较操作。

mismatch: 并行比较两个序列,指出第一个不匹配的位置,返回一对iterator,标志第一个不匹配元素位置。如果都匹配,返回每个容器的last。重载版本使用自定义的比较操作。

5.10集合算法

集合算法有4个。

set_union: 构造一个有序序列,包含两个序列中所有的不重复元素。重载版本使用自定义的比较操作。

set_intersection: 构造一个有序序列,其中元素在两个序列中都存在。重载版本使用自定义的比较操作。

set_difference: 构造一个有序序列,该序列仅保留第一个序列中存在的而第二个中不存在的元素。重载版本使用自定义的比较操作。

set_symmetric_difference: 构造一个有序序列,该序列取两个序列的对称差集(并集-交集)。

5.11堆算法

堆算法有4个。

make_heap: 把指定范围内的元素生成一个堆。重载版本使用自定义比较操作。

pop_heap: 并不真正把最大元素从堆中弹出,而是重新排序堆。它把first和last-1交换,然后重新生成一个堆。可使用容器的back来访问被"弹出"的元素或者使用pop_back进行真正的删除。重载版本使用自定义的比较操作。

push_heap: 假设first到last-1是一个有效堆,要被加入到堆的元素存放在位置last-1,重新生成堆。在指向该函数前,必须先把元素插入容器后。重载版本使用指定的比较操作。

sort_heap: 对指定范围内的序列重新排序,它假设该序列是个有序堆。重载版本使用自定义比较操作。

6小结

C++提供了一组强大的库,这些库提供了很多常见的编程问题的解决办法以及简化其他问题的工具。STL是其中一个非常重要的库。它采用了泛型编程的思想,通过使用模板使得算法独立于存储的数据类型,通过迭代器使得算法独立于容器类型。STL很好很强大,熟练使用它将使你如虎添翼,但是能够熟练的使用也非一日之寒,只能在漫漫编码过程中实践才能信手拈来,得心应手。

发布了76 篇原创文章 · 获赞 63 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/bjtuwayne/article/details/88725993