C++系列3:C++11 STL

Posted IE06

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++系列3:C++11 STL相关的知识,希望对你有一定的参考价值。

首先,c++11之后基本相当于换了一门语言,用cout << __cplusplus << endl;确认,如果出现的头六位数是大于等于201103的,则支持C++11。
这里首先讲STL,英文全称 standard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。

1. 远古方式

这里首先介绍一下传统方法如何建立数组:

  • 静态 int array[100];   定义了数组 array,并未对数组进行初始化
  • 静态 int array[100] = {1,2};  定义并初始化了数组 array
  • 动态 int* array = new int[100]; delete []array;  分配了长度为 100 的数组 array
  • 动态 int* array = new int[100]{1,2};  delete []array; 为长度为100的数组array初始化前两个元素
    数组如果用了动态数组(使用指针),注意用完了之后要delete释放

如何获取数组长度:
char str[20]=“0123456789”;
int a=strlen(str); // a=10; >>>> strlen 计算字符串的长度,以结束符 0x00 为字符串结束。
int b=sizeof(str); // 而 b=20; >>>> sizeof 计算的则是分配的数组 str[20] 所占的内存空间的大小,不受里面存储的内容改变。

2. 序列式容器

2.1 array

静态数组可以使用stl中的array,需要引入 array 头文件
在这里插入图片描述
array和下面的vector一样,都可以用[]和at()两种方式随机访问元素。

2.2 vector

使用vector需要include ,首先是基本用法。
在这里插入图片描述
它和下面deque的最主要区别,莫过于它有一个insert和emplace的语法。emplace的效率更高:
在这里插入图片描述

其次是迭代器,核心是指针也可以用++运算符。
在这里插入图片描述
vector 容器还提供了 2 个成员函数,即 front() 和 back(),它们分别返回 vector 容器中第一个和最后一个元素的引用,通过利用这 2 个函数返回的引用,可以访问(甚至修改)容器中的首尾元素。

2.3 deque

deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。
deque 容器也可以根据需要修改自身的容量和大小。
在这里插入图片描述

2.4 list

双向链表,不能随机访问。实际场景中,如何需要对序列进行大量添加或删除元素的操作,而直接访问元素的需求却很少,这种情况建议使用 list 容器存储序列。
在这里插入图片描述
通过 front() 和 back() 成员函数,可以分别获得 list 容器中第一个元素和最后一个元素的引用形式。举个例子:
在这里插入图片描述
在这里插入图片描述

2.5 forward_list

单向链表,擅长在序列的任何位置进行插入元素或删除元素的操作,但对于访问存储的元素,没有其它容器(如 array、vector)的效率高。
另外,由于单链表没有双向链表那样灵活,因此相比 list 容器,forward_list 容器的功能受到了很多限制。比如,由于单链表只能从前向后遍历,而不支持反向遍历,因此 forward_list 容器只提供前向迭代器,而不是双向迭代器。这意味着,forward_list 容器不具有 rbegin()、rend() 之类的成员函数。
在这里插入图片描述
forward_list 容器中是不提供 size() 函数的,但如果想要获取 forward_list 容器中存储元素的个数,可以使用头文件 中的 distance() 函数。
在这里插入图片描述

3. 关联式容器

关联式容器在存储元素值的同时,还会为各元素额外再配备一个值(又称为“键”,其本质也是一个 C++ 基础数据类型或自定义类型的元素),它的功能是在使用关联式容器的过程中,如果已知目标元素的键的值,则直接通过该键就可以找到目标元素,而无需再通过遍历整个容器的方式。
弃用序列式容器,转而选用关联式容器存储元素,往往就是看中了关联式容器可以快速查找、读取或者删除所存储的元素,同时该类型容器插入元素的效率也比序列式容器高。

3.1 map和multimap

和 map 容器唯一的不同在于,multimap 容器中存储元素的键可以重复。下面是最简单的使用方法:
在这里插入图片描述

3.2 使用pair

pair 类模板定义在头文件中。
在这里插入图片描述

3.3 set和multiset

在这里插入图片描述

3.4 无序关联式容器

实际场景中如果涉及大量遍历容器的操作,建议首选关联式容器;反之,如果更多的操作是通过键获取对应的值,则应首选无序容器。
在这里插入图片描述
在这里插入图片描述

3. 容器适配器

容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。
介绍 3 种容器适配器,分别是 stack、queue、priority_queue
在这里插入图片描述

3.1 stack

stack 栈适配器是一种单端开口的容器(如图 1 所示),实际上该容器模拟的就是栈存储结构,即无论是向里存数据还是从中取数据,都只能从这一个开口实现操作。
在这里插入图片描述
在这里插入图片描述

3.2 queue

和 stack 栈容器适配器不同,queue 容器适配器有 2 个开口,其中一个开口专门用来输入数据,另一个专门用来输出数据,如图 1 所示。
在这里插入图片描述

在这里插入图片描述

3.3 priority_queue

底层采用堆结构存储数据,称为优先级队列。

priority_queue 容器适配器中元素的存和取,遵循的并不是 “First in,First out”(先入先出)原则,而是“First in,Largest out”原则。直白的翻译,指的就是先进队列的元素并不一定先出队列,而是优先级最大的元素最先出队列。

和 queue 一样,priority_queue 也没有迭代器,因此访问元素的唯一方式是遍历容器,通过不断移除访问过的元素,去访问下一个元素。
在这里插入图片描述

4. 算法

首先需要#include <algorithm>

4.1 sort

在这里插入图片描述

在这里插入图片描述
假设这样一种情境,有一个存有 100 万个元素的容器,但我们只想从中提取出值最小的 10 个元素,该如何实现呢?

通过前面的学习,读者可能会想到使用 sort() 或者 stable_sort() 排序函数,即通过对容器中存储的 100 万个元素进行排序,就可以成功筛选出最小的 10 个元素。但仅仅为了提取 10 个元素,却要先对 100 万个元素进行排序,可想而知这种实现方式的效率是非常低的。

对于解决类似的问题,C++ STL 标准库提供了更高效的解决方案,即使用 partial_sort() 或者 partial_sort_copy() 函数。
在这里插入图片描述

4.2 merge

merge() 函数用于将 2 个有序序列合并为 1 个有序序列,前提是这 2 个有序序列的排序规则相同(要么都是升序,要么都是降序)。并且最终借助该函数获得的新有序序列,其排序规则也和这 2 个有序序列相同。

举个例子,假设有 2 个序列,分别为5,10,15,20,25和7,14,21,28,35,42,显然它们不仅有序,而且都是升序序列。因此借助 merge() 函数,我们就可以轻松获得如下这个有序序列:
5 7 10 15 17 20 25 27 37 47 57
在这里插入图片描述
当 2 个有序序列存储在同一个数组或容器中时,如果想将它们合并为 1 个有序序列,除了使用 merge() 函数,更推荐使用 inplace_merge() 函数。
在这里插入图片描述

4.3 find

find() 函数本质上是一个模板函数,用于在指定范围内查找和目标元素值相等的第一个元素。
该函数会返回一个输入迭代器,当 find() 函数查找成功时,其指向的是在 [first, last) 区域内查找到的第一个目标元素;如果查找失败,则该迭代器的指向和 last 相同。
在这里插入图片描述

以上是关于C++系列3:C++11 STL的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL应用与实现5: 如何使用std::array (since C++11)

C++ STL应用与实现64: 如何使用shuffle和random_shuffle : 洗牌 (since C++11)

C++ STL应用与实现22: 函数组合之1:如何使用std::bind (since C++11)

swig c++ to perl : 如何使用 c++11 字符串 STL 函数

C++ STL应用与实现7: 如何使用std::forward_list 单链表 (since C++11)

C++ STL应用与实现26: 如何使用std::for_each以及基于范围的for循环 (since C++11)