STL(标准模板库),是目前C++内置支持的library。它的底层利用了C++类模板和函数模板的机制,由三大部分组成:容器、算法和迭代器。
目前STL有六大组件
- 容器 container
- 算法 algorthm
- 迭代器 iterator
- 仿函数 function object
- 适配器 adaptor
- 空间配置器 allocator
下面,我们会一一进行介绍。
STL初探
容器是STL中很重要的一种数据结构。常见的容器包括
- vector容器
- deque双端数组
- stack栈模型
- queue队列模型
- list链表模型
- priotriy_queue优先级队列
- set与multiset容器
- map与multimap容器
除了容器,STL还封装了强大的算法,能够实现查找、删除、替换、删除等很多常见操作。后面会重点讲解。
另外,迭代器也是STL重要的一环,通过迭代器,我们可以很方便对容器中的元素进行遍历,以及操作容器。后面我们会穿插讲解迭代器。
STL中的string
string
是STL的字符串类型,在C语言中,我们通常用char *
或者char[]
字符数组来表示字符串。C++的string
和C语言的char *
有什么区别呢?
string
是一个类,char *
是指向字符的指针string
封装了char *
,管理这个字符串,是一个char *
类型的容器string
不用考虑内存释放和数组越界string
提供了一些列的字符串操作函数
string的构造函数
既然string是一个类,那么也就有构造函数,我们研究下string的构造函数。
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//通过const char * 初始化
string s1 = "aaaa";
//构造函数初始化
string s2("bbbbb");
//通过拷贝构造函数来初始化对象s3
string s3 = s2;
//用10个'a'字符来初始化字符串
string s4(10, 'a');
return 0;
}
字符串的遍历
字符串的遍历,有三种遍历的方式
- 数组方式遍历,通过[]操作符遍历 (不会抛出异常)
- at()方法遍历,根据index取值 (会抛出异常)
- 通过STL迭代器遍历
int main(int argc, const char * argv[]) {
//创建字符串对象
string str("abcdefg");
//数组形式遍历
for (int i = 0; i < str.length(); i++) {
cout<< str[i] << endl;
}
//at方法遍历
for (int i = 0; i < str.length(); i++) {
cout << str.at(i) << endl;
}
//迭代器遍历
for (string::iterator it = str.begin(); it != str.end(); it++) {
cout << *it << endl;
}
return 0;
}
数组方式和at方法方式,有一个明显的不同
- 数组方式,如果出现越界或者其他错误,不会抛出异常,程序直接终端。
- at()方法遍历,出现越界或其他错误,会抛出异常,程序可以处理异常。
迭代器其实可以看作是一个字符的指针,上个例子中string::iterator it = str.begin()
就是定义一个string类型的迭代器,指向str
的第一次位置。*it
就表示当前的字符。注意str.end()
表示字符串最后一个字符的后面一个位置。如果it == str.end()
就表示已经遍历到终点了。
string与char *的转换
string提供了成员函数c_str
来将string对象转化成const char *
。string提供了copy(buf,size,begin)
成员函数来讲string从begin
位置开始的size
个字符拷贝到buf
中。需要注意的是:
- 如果buf容纳不下,会越界
- 拷贝过去后,不会转变成C风格的字符串,也就是不会在buf后面添加'\0'
int main(int argc, const char * argv[]) {
//1 string转char *
string str("aaaaaa");
const char *p = str.c_str();
//2 char *转string
const char *p1 = "12345";
string str2 = p1;
//3 string拷贝到buf[]中
char buf[128] = {0};
//从0开始,拷贝3个字符到buf指向的内存空间
//如果buf空间容纳不下,会越界
//拷贝过去时,不会给buf末尾添加\0
str.copy(buf, 3, 0);
return 0;
}
string的拼接
string为我们提供了两种字符串拼接方式,一种是重写了 +
操作符,我们可以直接将连个字符串相加,类似于java的语法。另一种是string提供了成员函数append()
供我们拼接连个字符串.
int main(int argc, const char * argv[]) {
string s1 = "123456";
string s2 = "abcdef";
//直接使用加号运算符拼接
string s3 = s1 + s2;
//使用成员函数拼接
string s4 = s1.append(s2);
cout<<s3<<endl;
cout<<s4<<endl;
return 0;
}
string的查找和替换
string类提供了find
函数,用来查找字符串中指定的字符。提供了replace
函数,用来替换字符串中指定位置的字符串。
replace
函数是,先删除指定位置,指定长度的字符,然后在当前指定位置插入新的字符。
int main(int argc, const char * argv[]) {
string s1 = "hello hello hello hello hello hello 1234 7876";
//从0位置开始查找第一个hello出现的首位位置
size_t index1 = s1.find("hello",0);
cout << index1 << endl;
//查找第一个hello出现时的首位位置
size_t index2 = s1.find_first_of("hello");
cout << index2 << endl;
//查找最后一个hello出现时的末尾位置
size_t index3 = s1.find_last_of("hello");
cout << index3 << endl;
//求hello出现的次数,以及对应的下标
int count = 0;
size_t offindex = s1.find("hello",0);
while (offindex != string::npos) { //如果 offindex != -1
//找到了
cout << "索引:" << offindex <<endl;
count++;
offindex++;
offindex = s1.find("hello", offindex);
}
//把hello替换成welcome
size_t offindex1 = s1.find("hello", 0);
while (offindex1 != string::npos) {
//从offindex1的位置开始删除5个位置,并插入新的字符串welcome
s1.replace(offindex1, strlen("hello"), "welcome");
//从后面的位置开始
offindex1 += strlen("welcome");
//继续查找
offindex1 = s1.find("hello", offindex1);
}
cout << "替换后的字符串:" << s1 <<endl;
return 0;
}
string区间删除和插入
string提供了insert
和erase
分别实现插入和删除操作。
插入:pos位置插入字符串s,返回新的string。
string &insert(int pos, const char *s)
string &insert(int pos, const string &s)
插入:pos位置插入n个字符c,返回string。
string &insert(int pos, int n, char c)
删除:删除从pos位置开始的n个字符,返回新的string
string &erase(int pos, int n)
删除:删除指定迭代器的位置,返回当前迭代器位置
string::iterator erase(string::iterator it)
删除:删除迭代器之间的字符,左闭右开区间
string::iterator erase(string::iterator beginIt, string::iterator endIt)
int main(int argc, const char * argv[]) {
string s1 = "hello1 world!";
//1 删除字符串中的'1'
//---通过find函数,查找'1'所在的迭代器位置
string::iterator it = find(s1.begin(), s1.end(), '1');
//---删除
if (it != s1.end()) {
s1.erase(it);
}
cout << s1 << endl;
//2 删除起始迭代器位置的字符
s1.erase(s1.begin(), s1.begin() + 3);
cout << s1 << endl;
//3 在0位置插入"AAA"
s1.insert(0, "AAA");
cout << s1 << endl;
return 0;
}
string算法相关
目前常见的string的算法是大小写转换。一般使用函数transform
来进行转换。
int main(int argc, const char * argv[]) {
string s1 = "abcdefg";
string s2 = "AEDLFLKJDLKJFL";
//小写全部转换成大写,转换的结果放在s1.begin()的位置,后面的操作需要强制转换成指定的函数类型
transform(s1.begin(), s1.end(), s1.begin(), (int (*)(