STL简介

标准模板库是一组模板类和函数,向程序员提供了:

  1. 用于储存信息的容器
  2. 用于访问容器储存的信息的迭代器
  3. 用于操作容器内容的算法

其中,容器又包含:

  • 顺序容器

    • std::vector——与动态数组类似,在最后插入数据。
    • std::deque——与std::vector类似,允许在开头添加或删除数据。
    • std::list——与双向链表类似。
    • std::forward_list——类似于std::list,不过是单向链表。
  • 关联容器

    • std::set——储存各不相同的值,在插入时进行排序。(对数复杂度)
      std::unordered_set——c++11新增的,与set相同。(复杂度为常数)

    • std::map——储存键值对,并根据唯一的键排序。(对数复杂度)
      std::unordered_map——c++11新增的,与map相同。(复杂度为对数)

    • std::multiset——与set类似,但值不需要是唯一的。
      std::unordered_multiset——c++11新增的,与unordered_set类似。但值不需要是唯一的。

    • std::multimap——与map类似,不要求键是唯一的。
      std::unordered_multimap——c++11新增的,与unordered_map类似。不要求键是唯一的。

  • 容器适配器

    • std::stack:以LIFO(后进先出)的方式储存元素。
      • std::queue:以FIFO(先进先出)的方式储存元素。
      • std::priority_queue:以特定顺序储存元素。

下文再介绍时,省略了std::

STL迭代器

指针是最简单的迭代器,让该指针指向数组中的第一个元素,然后递增指针以获得下一个元素。
STL中的迭代器是模板类,在某种程度上,可以将它理解成泛型指针。

STL算法

为程序员提供的查找、排序、反转等功能的模板函数。
使用STL算法时,要包含标准头文件

常用STL算法如下:

  • std::find: 在集合中查找值。
  • std::find_if: 根据用户指定的谓词在集合中查找值。
  • std::reverse: 反转集合中的元素的排序。
  • std::remove_if: 根据用户定义的谓词将元素从集合中删除。
  • std::transform: 使用用户定义的变换函数对容器中的元素进行变换。

使用迭代器在容器和算法之间交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>   
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
vector<int> IntArray;
IntArray.push_back(123);
IntArray.push_back(1997);
IntArray.push_back(917);
IntArray.push_back(2019);
IntArray.push_back(6666);

//使用迭代器遍历容器元素
//for (vector<int>::iterator IA = IntArray.begin();
// IA < IntArray.end(); ++IA) {
// cout << *IA << endl;
//}
//使用迭代器遍历容器元素,此处所使用了auto让编译器自动判断类型
for (auto iArrayWalker = IntArray.begin();
iArrayWalker < IntArray.end(); ++iArrayWalker){
cout << *iArrayWalker << endl;
}
//使用find算法在容器中查找元素1997,查到末尾时(end())还没找到,便返回end()的地址
//vector<int>::iterator value = find(IntArray.begin(), IntArray.end(), 1997);
auto value = find(IntArray.begin(), IntArray.end(), 1997);

//判断是否找到元素1997
if (value != IntArray.end()) {
cout << "value: " << *value << endl;
//获取1997在容器中的位置,及到begin()的距离
int index = distance(IntArray.begin(), value);
cout << "index: " << index << endl;
}
getchar();
return 0;
}

由上述代码可以看出,迭代器就是获得的是容器中元素的地址;因此,在某种程度上可以将它理解为泛型指针。

STL string类

std::stirng与std::wstring是STL库中一个帮助程序员用于字符串操作的容器类。使用时要包含头文件。
以std::string为例来介绍这个类的用法。

  • 实例化string
1
2
3
4
5
6
7
8
9
10
11
12
13
const char* C_StyleString = "Hello String";
const char* cString = "Hello String";
//使用构造函数初始化
string str(cString);
//使用等号初始化
string str1 = cString;
//使用string类型数据初始化
string strCopy(cString);
//使用某个字符串的前n位初始化
string str2("Hello String", 5);
//使用指定数量的字符初始化
string str3(6, 'a'); //str3 = aaaaaa
//string str3(6, 'adf'); //str3 = ffffff
  • 访问string的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//通过[]访问元素
for (int i = 0; i < str.length(); ++i) {
cout << str[i] << endl;
}
//通过迭代器访问
for (string::const_iterator pos = str.begin()
; pos != str.end()
; ++pos)
{
//*pos = 'h'; //报错,pos指向的值是const类型的,不可更改
cout << *pos << endl;
}
//通过迭代器访问
for (string::iterator pos = str.begin()
; pos != str.end()
; ++pos)
{
*pos = '6'; //不报错
cout << *pos << endl;
}

上面代码中使用迭代器时,使用了一个新的迭代器const_iterator,使用它时,迭代器的值可变,但迭代器指向的值的值不可被改变。

  • 字符串拼接

使用+=或者成员函数append()来拼接字符串。

1
2
3
4
5
6
string str4 = "Hello ";
string str5 = "World ";
string str6("Beautiful!");

str4 += str5; //str4 = Hello World
str4.append(str6); //str4 = Hello World Beautiful!
  • 字符/子字符串查找

可以使用string中的成员函数find来查找字符或者子字符串。
查找成功返回字符的索引或子字符串首个字符的索引。
查找失败返回string::npos(实际值为-1)。

1
2
3
4
5
6
7
8
9
10
string str6 = "Hello World";
//从索引为0初的字符往后进行查找
int index = str6.find("World", 0);
cout << index << endl; //6
//查找str6中所有 l 的索引
size_t charPos = str6.find('l', 0);
while (charPos != string::npos) {
cout << charPos << endl; //2 3 9
charPos = str6.find('l', ++charPos);
}

size_t在32位架构上是4字节,在64位架构上是8字节,在不同架构上进行编译时需要注意这个问题。而int在不同架构下都是4字节;且int为带符号数,size_t为无符号数。

  • 字符串截短
    可以使用成员函数erase()来删除字符串中的字符。
    使用方法如下:
1
string myStr = "Life is always like this.";
  1. 在给定偏移位置(索引值)和指定数目时删除字符。
1
2
//删除索引在 区间[14,19) 内的字符串
myStr.erase(14,5); //Life is always this.
  1. 删除迭代器iChar指向的字符。
1
2
auto iChar = find(myStr.begin(), myStr.end(), '.');
myStr.erase(iChar); //Life is always like this
  1. 删除两个迭代器指定范围内的字符串。
1
myStr.erase(++myStr.begin(), myStr.end());	//L

使用成员方法clear()时,经清楚全部内容并重置string对象。

  • 字符串反转

使用泛型算法std::reverse()对字符串进行反转。(注意不是成员方法)
reverse接收两个参数,起始迭代器、终止迭代器,然后将对两个迭代器之间的内容进行反转。

1
2
string myStr = "Life is always like this.";
reverse(++myStr.begin(), myStr.end()); //L.siht ekil syawla si efi
  • 字符串大小写转换

使用算法std::transform()进行大小写转换。(注意不是成员方法)
transform(first, last, r_first, trans)接收四个参数:开始迭代器、终止迭代器、开始迭代器、要执行的变换。
要执行转大写操作时 trans = toupper, 要执行转小写操作时 trans = tolower。

1
2
3
4
5
string myStr = "life is always like this.";
transform(++myStr.begin(), myStr.end(), ++myStr.begin(), toupper);
//——>lIFE IS ALWAYS LIKE THIS.
transform(++myStr.begin(), myStr.end(), ++myStr.begin(), tolower);
//——>life is always like this.

如果要编写的应用程序需要更好的支持非拉丁字符,如中文与日文时,应使用std::wstring。


 评论