C++标准模板库Stand Template Library(STL)简介与STL string类

参考《21天学通C++》第15和16章节,在对宏和模板学习之后,开启对C++实现的标准模板类STL进行简介,同时介绍简单的string类。虽然前面对于vector、deque、list等进行过学习和总结,但并没有一个宏观上的把握,现在通过上一篇和这一篇博文,将对C++模板以及基于C++模板的STL关联起来,形成一个总体的把握,对于掌握C++中模板(template)这一强有力的工具会十分有帮助。本文的主要内容有:

(1) STL容器;

(2) STL迭代器;

(3) STL算法;

(4) STL字符串类。

简单的来说,标准模板库是一组模板类和函数,向程序员提供了用于存储信息的容器、用于访问容器存储信息的迭代器和用于操作容器内容的算法。最后结合非常常用的STL string类进行介绍。

一、STL标准模板库

************************************************************************************************************************************1. STL容器

容器是用于存储数据的STL类,STL提供了两种类型的容器:顺序容器和关联容器。另外,还提供了容器适配器(Container Adapter)的类,它们是顺序容器和关联容器的变种,用于满足特殊需求。

(1) 顺序容器

按照顺序存储数据,比如数组和列表。顺序容器插入速度快但查找操作相对较慢。主要包括以下几种标准模板类实现:std::vector,操作与动态数组一样,在最后插入数据;std::deque,与vector类似,可在开头插入和删除元素;std::list,操作与双向链表一样,可视为链条,对象被连接在一起,可在任意位置插入和删除对象;std::forward_list,类似std::list,是单向链表,只能沿着一个方向遍历。

(PS:如果上面介绍的数据结构不太清楚的话,可以参考我的系列博文:数据结构(二):线性表的使用原则以及链表的应用-稀疏矩阵的三元组表示http://blog.csdn.net/lg1259156776/article/details/47073957数据结构(二):链表、链队列http://blog.csdn.net/lg1259156776/article/details/47018813数据结构(二):线性表包括顺序存储结构(顺序表、顺序队列和顺序栈)和链式存储结构(链表、链队列和链栈) http://blog.csdn.net/lg1259156776/article/details/46993591

正如上面博文中介绍的,vector和deque是顺序存储结构,而list是链式存储结构,vector和deque都是连续的内存组织,而list则可使用不连续的内存块组织,所以list不需要像vector和deque那样给内部数组重新分配内存。所以在使用中,涉及到频繁插入和删除操作的,一般使用链式存储结构的list,否则一般使用vector足矣。

(2) 关联容器

关联容器按指定的顺序存储数据,就像词典一样,这将降低插入数据的速度,但是在查询方面有很大的优势。

STL提供的关联容器包括:

std::set,存储各不相同的值,在插入时进行排序;容器的复杂度为对数。

std::unordered_set,存储各不相同的值,在插入时进行排序;容器的复杂度为常数。

std::map,存储键值对,并根据唯一的键排序;容器的复杂度为对数。

std::unordered_map,存储键值对,并根据唯一的键排序;容器的复杂度为对数。

std::multiset,与set类似,但允许存储多个值相同的项,即值不需要是唯一的。

std::unordered_multiset,与unordered_set类似,但允许存储多个值相同的项。

std::multimap,与map类似,但不要求键是唯一的。

std::unordered_multimap,与unordered_map类似,但不要求键是唯一的。

(3) 选择合适的容器

显然,可能有多种STL容器能够满足应用程序的需求,但哪一个是较好的选择呢?

下面对STL容器的特点进行梳理:

std::vector(顺序容器)的优点是在末尾插入数据时快(时间固定),可以像访问数组一样进行访问,缺点是调整大小时将影响性能,搜索时间与容器包含的元素个数成正比,只能在末尾插入数据;

std::deque(顺序容器)的优点是具备vector所有优点,还可以在容器开头插入数据,插入时间固定。缺点是:vector所有缺点,与vector不同的是根据规范,deque不需要支持reserve函数,该函数让程序元能够给vector预留内存空间,以免频繁地调整大小,从而提高性能。

std::list(顺序容器)的优点是在list开头、中间或末尾插入数据,所需时间都是固定的,将元素从list中删除所需的时间是固定的,而不管元素的位置如何,插入或删除元素后,指向list中其他元素的迭代器仍然有效,缺点是不能像数组那样能够根据索引随机访问元素,搜索速度比vector慢,因为元素没有存储在连续的内存单元中,搜索时间与容器的个数成正比。

std::forward_list(顺序容器)优点是单向链表类,只能沿一个方向遍历,缺点是只能使用push_front在链表表头插入元素。

std::set(关联容器),搜索时间不是与容器中的元素个数而是与元素个数的对数成正比,因此搜索速度通常比顺序容器要快,缺点是元素的插入速度比顺序容器慢,因为插入时要进行排序。

std:unordered_set(关联容器),搜索、插入和删除速度几乎不受容器元素个数的影响。缺点是由于元素未被严格排序,因此不能依赖于元素在容器中的相对位置。

std::multiset(关联容器)优点是需要存储非唯一值时,应使用;缺点是插入速度可能比顺序容器要慢,因为在插入时对元素键值对进行排序。

std::unordered_multiset(关联容器)优点是需要存储非唯一值时,搜索、插入和删除速度几乎不受容器元素个数的影响。缺点是由于元素未被严格排序,因此不能依赖于元素在容器中的相对位置。

std::map(关联容器)优点是可用于存储键值对,搜索时间与元素个数的对数成正比,因此搜索速度通常比顺序容器要快的多。缺点是插入时进行排序,因此插入速度比顺序容器要慢。

std::unordered_map(关联容器)优点是搜索、插入和删除元素的时间固定,不受容器长度的影响。缺点是元素未被严格排序,不适合用于顺序很重要的情形。

std::multimap(关联容器)优点是在需要存储键值对且要求键值不唯一时,可用。缺点是插入时需要排序,因此插入速度比顺序容器要慢。

std::unordered_multimap(关联容器)优点是在需要存储键值对且要求键值不唯一时可用。缺点是由于元素未被严格排序,因此不能依赖于元素在容器中的相对位置。

(4) 容器适配器

是顺序容器和关联容器的变种,其功能有限,用于满足特定的需求,主要的容器适配器有:

std::stack,以后进先出的方式存储元素,能够在栈顶压入和弹出元素;

std::queue,以先进先出的方式存储元素,能够删除最先插入的元素;

std::priority_queue,以特定的顺序存储元素,因为优先级最高的元素总是位于队列开头。

************************************************************************************************************************************

2. STL迭代器

最简单的迭代器是指针,给定一个指向数组中第一个元素的指针,可递增该指针使其指向下一个元素,还可以直接对当前位置的元素进行操作。

STL中的迭代器是模板类,从某种程度上说,它是泛型指针,能够对STL各种容器进行访问。注意,操作也可以是以模板函数的方式提供的STL算法,迭代器是一个桥梁,用来沟通STL算法和STL容器。

STL提供的迭代器分为两大类,一是输入迭代器,通过对输入迭代器解除引用,它将引用对象,而对象可能位于集合中,最严格的输入迭代器确保只是以只读的方式访问对象;二是输出迭代器,输出迭代器让程序员对集合执行写入操作,最严格的输出迭代器确保只能执行写入操作。

以上两种迭代器可进一步分为三种:一是前向迭代器,允许输入和输出,还可以是const只读的,前向迭代器通常用于单向链表;二是双向迭代器,可对其进行递减操作,从而向后移动,常用于双向链表;三是随机访问迭代器,常用于访问数组。

************************************************************************************************************************************

3. STL算法

对应STL中的容器,STL实现了一系列的模板函数。查找、排序和翻转都是标准的编程需求,不应让程序员重复实现这样的功能,因此,以STL以STL算法的方式提供这些函数,通过结合使用这些函数和迭代器,程序员可对容器执行一些最常见的操作,比如:

std::find,在集合中查找值;

std::find_if,根据用户提供的谓词在集合中查找值;

std::reverse,翻转集合中的元素;

std::remove_if,根据用户定义的谓词在集合中删除元素;

std::transform,使用用户定义的变换函数对容器中的元素进行变化。

************************************************************************************************************************************

4. STL string类

STL提供了一个专门操作字符串而设计的模板类,std::basic_string<T>该模板类两个常用的具体化如下:

std::string,基于char型的std::basic_string具体化,用于操作简单的字符串;

std::wstring,基于wchar_t的std::basic_string具体化,用于操作宽字符串。

************************************************************************************************************************************

二、STL string类

下面主要针对string具体化进行介绍:

std::string是一个类似于动态字符串的数据结构,通常的字符串的存储结构是基于字符数组的,但是其长度是固定(static),使用起来十分不方便。使用string能够有以下的优势:

减少在创建和操作字符串方面的工作量;

在内部管理内存分配细节,从而提高了应用程序的稳定性;

提供了复制构造函数和赋值运算符,可确成员字符串得以正确复制;

提供了帮助执行复制、截短、查找和删除的使用函数。

提供了用于比较的运算符;

1. 使用STL string类

(1) 基本操作

最常用的字符串函数包括:复制、连接、查找字符和字符串、截短、使用标准模板库提供的算法进行字符转反转和大小写转换。必须包含<string>

(2) 实例化和复制STL string

使用常量字符串初始化,赋值操作即可。

std::string str("test")

(3) 访问string的字符内容

string的访问可以使用迭代器,也可以采用数组的语法下标运算符[]来提供偏移量。要获得string对象的C风格表示,可使用成员函数c_str(),转变为char* 的表示。

string::const_iterator iCharacterLocator;

 (4) 拼接字符串

可使用+=来操作,也可以使用成员函数append,append函数有多个重载版本,能够接受一个string,也可以接受C风格的char* 字符串。

(5) 查找字符串或查找字符

成员函数find(),该函数有多个重载版本,可在给定的string对象中查找字符或字符串。还提供了一些与find类似的函数如:find_first_of(),find_first_not_off,find_last_off(),find_last_not_off。

(6) 截短字符

可使用erase函数,在给定偏移量和字符数时删除指定数目的字符;在给定指向字符的迭代器时删除该字符;在给定由两个迭代器指定的范围时删除该范围内的字符。string类还提供了clear,用来清除所有的内容,并重置string对象。

(7) 字符串反转

有时需要翻转字符串的内容,假设要判定用户输入的字符串是否回文,方法之一就是将其翻转,再与原来的字符串比较。翻转STL string很容易,只需要使用泛型算法:std::reverse即可。通过迭代器输入翻转的范围,可以在一部分的字符串上进行翻转。

(8) 字符串的大小写转换

可使用算法transform,它对集合中的每一个元素都执行一个用户指定的转换函数,这里集合是string对象本身。


如果应用程序需要支持非拉丁文字符,如中文和日文,应使用std::wstring,其操作方式与string一样。


小结:

STL string类是模板库提供的一个容器,可满足程序员众多字符串操作,优点是原来由程序员负责维护的内存等操作,将有STL框架提供的一个容器类完成。

***********************************************************************************************************************************

2015-7-31


posted @ 2015-07-31 15:22  ZhangPYi  阅读(171)  评论(0编辑  收藏  举报