C++ 提高篇 2 之 STL 及 string 容器
STL 初识
STL 基本概念
- STL 标准模板库
- STL 从广义上分为:容器、算法和迭代器
- 容器和算法之间通过迭代器进行无缝连接
- STL 几乎所有的代码都采用了模板类或者模板函数
STL 六大组件
》》STL 大体上分为六大组件,分别是容器、算法、迭代器、仿函数、适配器和空间配置器
- 容器:各种数据结构,如 vector、list、deque、set、map 等,用来存放数据
- 算法:各种常用的算法,如 sort、find、copy、for_each 等
- 迭代器:扮演了容器和算法之间的胶合剂
- 仿函数:行为类似函数,可作为算法的某种策略
- 适配器:一种用来修饰容器、仿函数或者迭代器接口的东西
- 空间配置器:负责空间的配置与管理
STL 中容器、算法和迭代器
》》容器
- STL 容器就是运用一些最广泛的数据类型实现出现
- 常用的数据结构:数组、链表、树、栈、队列、集合、映射表等
- 可以分为序列式容器和关联式容器二类
- 序列式容器强调值的排序,其中的元素都有固定的位置
- 关联式容器属于二叉树结构,其中的元素没有固定的位置关系
》》算法
- 有限的步骤解决逻辑或数学上的问题,称为算法
- 算法分为质变算法和非质变算法二类
- 质变算法指运算过程会改变区间元素内容,如拷贝、替换和删除等
- 非质变算法指运算过程不会改变区间元素内容,如查找、计数、遍历和寻找极值等
》》迭代器
- 提供一种方法,使之能够依序访问容器中的每个元素,而又无需暴露容器内部的表示方式
- 每个容器都有属于自己的迭代器,迭代器的使用非常类似于指针
- 迭代器可以分为输入、输出、前向、双向、随机迭代器
vector 存放内置数据类型
容器:vector
(所需头文件 #include <vector>
)
算法:for_each
(所需头文件 #include <algorithm>
)
迭代器:vector<int>::iterator
#include <iostream>
using namespace std;
#include <vector> // 容器
#include <algorithm> // 算法
void Print(int value) {
cout << value << " ";
}
int main() {
// 1. 创建一个 vector 容器,数组
vector<int> v;
// 2. 向容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
// 3. 通过迭代器访问容器中的数据
vector<int>::iterator itBegin = v.begin(); // 起始迭代器,指向容器中的第一个元素
vector<int>::iterator itEnd = v.end(); // 结束迭代器,指向容器中最后一个元素的下一个位置
// itBegin 和 itEnd 都属于指针
// 3.1 第一种遍历方法
while (itBegin != itEnd) {
cout << *itBegin << " "; // 10 20 30
itBegin++;
}
cout << endl;
// 3.2 第二种遍历方法
for (vector<int>::iterator it = v.begin(); it < v.end(); it++) {
cout << *it << " "; // 10 20 30
}
cout << endl;
// 3.3 第三种遍历方法 -- 利用 STL 提供遍历的算法
for_each(v.begin(), v.end(), Print); // 10 20 30
cout << endl;
system("pause");
return 0;
}
- 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
- 39
- 40
- 41
解释:如下程序创建了一个容器数组 v;并利用 push_back 函数插入了三条 int 类型的数据;随后通过迭代器访问数组中的元素:访问方法如下举了三个例子,第一种和第二种类似,用二个变量接收容器 v 的起始地址和末尾后(末尾后一个)地址,用遍历的方式访问元素,第三种则是通过算法 for_each,其中传入了三个参数,第一个和第二个参数分别是起始地址和末尾后地址,第三个参数传递了一个函数名,函数形参为数组中的元素
vector 存放自定义数据类型
自定义 Person 数据类型,其中包含二个成员属性(Name_ 和 Age_)
第一种:vector 容器数组中存放 Person 对象
#include <iostream>
using namespace std;
#include <string>
#include <vector> // 容器
// 自定义数据类型
class Person {
public:
Person(string name, int age) {
Name_ = name;
Age_ = age;
}
public:
string Name_;
int Age_;
};
int main() {
// 1. 创建容器对象
vector<Person> v;
// 2. 创建数据并插入数据
Person p1("A", 1);
Person p2("B", 2);
Person p3("C", 3);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
// 3. 输出数组中的数据
for (vector<Person>::iterator it = v.begin(); it < v.end(); it++)
{
cout << "Name:" << (*it).Name_ << " Age:" << (*it).Age_ << endl;
}
// outputs:Name:A Age:1
// Name:B Age:2
// Name:C Age:3
system("pause");
return 0;
}
- 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
- 39
- 40
- 41
- 42
第二种:vector 容器数组中存放 Person 对象地址
#include <iostream>
using namespace std;
#include <string>
#include <vector> // 容器
// 自定义数据类型
class Person {
public:
Person(string name, int age) {
Name_ = name;
Age_ = age;
}
public:
string Name_;
int Age_;
};
int main() {
// 1. 创建容器对象
vector<Person*> v;
// 2. 创建数据并插入数据地址
Person p1("A", 1);
Person p2("B", 2);
Person p3("C", 3);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
// 3. 输出数组中的数据 -- 此时 *it 变为一个指针
for (vector<Person*>::iterator it = v.begin(); it < v.end(); it++)
{
cout << "Name:" << (*it)->Name_ << " Age:" << (*it)->Age_ << endl;
}
// outputs:Name:A Age:1
// Name:B Age:2
// Name:C Age:3
system("pause");
return 0;
}
- 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
- 39
- 40
- 41
- 42
vector 容器嵌套容器
#include <iostream>
using namespace std;
#include <string>
#include <vector> // 容器
// 自定义数据类型
class Person {
public:
Person(string name, int age) {
Name_ = name;
Age_ = age;
}
public:
string Name_;
int Age_;
};
int main() {
// 1. 创建容器对象
vector<vector<int>> v;
// 2. 创建数据对象并为之插入数据 -- 次容器
vector<int> v1;
vector<int> v2;
vector<int> v3;
for (int i = 0; i < 3; i++) {
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
}
// 3. 往主容器中插入数据
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
// 4. 遍历主容器对象
for (vector<vector<int>>::iterator it = v.begin(); it < v.end(); it++) {
for (vector<int>::iterator iit = (*it).begin(); iit < (*it).end(); iit++) {
cout << (*iit) << " ";
}
cout << endl;
}
// outputs:1 2 3
// 2 3 4
// 3 4 5
system("pause");
return 0;
}
- 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
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
string 容器
string 基本概念
本质
string 是 C++ 风格的字符串,而 string 本质上是一个类
string 和 char * 的区别
- char * 是一个指针
- string 是一个类,类内部封装了 char *,是一个 char * 型的容器
特点
- string 类内部封装了很多成员方法,如查找、拷贝、删除、替换和插入等
- string 管理 char * 所分配的内存,不用担心复制越界和取值越界问题
string 构造函数
构造函数原型
string();
// 创建一个空的字符串,如 string str;string(const char * s);
// 使用字符串 s 初始化string(const string& s);
// 使用一个 string 对象初始化另一个 string 对象string(int n, char c);
// 使用 n 个字符 c 初始化
#include <iostream>
using namespace std;
#include <string>
int main() {
// 1. 默认构造
string s1;
cout << s1 << endl; // 空字符串
// 2. 有参构造
const char * str = "love"; // C 风格字符串
string s2(str);
cout << s2 << endl; // love
// 3. 使用一个 string 对象初始化字符串
string s3(s2);
cout << s3 << endl; // love
// 4. 使用 n(10) 个字符 c(g) 初始化
string s4(10, 'g');
cout << s4 << endl; // gggggggggg
system("pause");
return 0;
}
- 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
string 赋值操作
赋值的函数原型
string& operator=(const char* s);
// 字符串 s 赋值给当前的字符串string& operator=(const string &s);
// 字符串对象 s 赋值给当前的字符串string& operator=(char c);
// 字符赋值给当前的字符串string& assign(const char *s);
// 字符串 s 赋值给当前的字符串string& assign(const char *s, int n);
// 字符串 s 的前 n 个字符赋值给当前的字符串string& assign(const string &s);
// 字符串对象 s 赋值给当前字符串string& assign(int n, char c);
// 将 n 个字符 c 赋值给当前字符串
#include <iostream>
using namespace std;
#include <string>
int main() {
// 默认构造
string s1; // 空字符串
// 有参构造
string s2("you");
// 使用 5 个 r 初始化字符串
string s3(5, 'r');
// 等号赋值操作
// 1. 字符串 "love" 赋值给字符串 s1
s1 = "love";
cout << s1 << endl; // love
// 2. 字符串对象 s2 赋值给 s1
s1 = s2;
cout << s1 << endl; // you
// 3. 字符对象 c 赋值给字符串 s1
s1 = 'm';
cout << s1 << endl; // m
// assign 函数赋值操作
// 1. 字符串 "his" 赋值给字符串 s1
s1.assign("his");
cout << s1 << endl; // his
// 2. 字符串 "his" 前 n 个元素赋值给字符串 s1
s1.assign("her", 2);
cout << s1 << endl; // he
// 3. 字符串 s3 赋值给字符串 s1
s1.assign(s3);
cout << s1 << endl; // rrrrr
// 4. 将 n(5) 个字符 c(b) 赋值给字符串 s1
s1.assign(5, 'b');
cout << s1 << endl; // bbbbb
system("pause");
return 0;
}
- 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
- 39
- 40
- 41
string 字符串拼接
字符串拼接的函数原型(append 函数不可拼接字符)
string& operator+=(const char * s);
// 拼接字符串 sstring& operator+=(const char c);
// 拼接字符 cstring& operator+=(const string & s);
// 拼接字符对象 sstring& append(const char *s);
// 拼接字符串 sstring& append(const char *s, int n);
// 拼接字符串 s 的前 n 个字符string& append(const string &s);
// 拼接字符串对象 sstring& append(const string &s, int pos, int n);
// 拼接从索引 pos 开始的 n 个字符
#include <iostream>
using namespace std;
#include <string>
int main() {
// 构造函数
string s1; // 空字符串
// 有参构造
string s2("you");
// 加等号拼接字符串
// 1. 拼接字符串 s
s1 += "i";
cout << s1 << endl; // i
// 2. 拼接字符 c
s1 += 'l';
cout << s1 << endl; // il
// 3. 拼接字符串对象 s2
s1 += s2;
cout << s1 << endl; // ilyou
// append 函数拼接字符串
// 1. 拼接字符串 s
s1.append("beat");
cout << s1 << endl; // ilyoubeat
// 2. 拼接字符串 s 的前 n 个字符
s1.append("ful", 2);
cout << s1 << endl; // ilyoubeatfu
// 3. 拼接字符串对象 s2
s1.append(s2);
cout << s1 << endl; // ilyoubeatfuyou
// 4. 拼接字符串从索引位置 2 开始的 2 个字符
s1.append("abcdefg", 2, 2);
cout << s1 << endl; // ilyoubeatfuyoucd
system("pause");
return 0;
}
- 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
- 39
string 查找和替换
字符串查找:查找指定字符串是否存在
int find(const string& s, int pos = 0) const;
// 从索引为 pos 往后查找字符串对象 s 第一次出现的位置int find(const char* s, int pos = 0) const;
// 从索引为 pos 往后查找字符串 s 第一次出现的位置int find(const char* s, int pos, int n) const;
// 从索引为 pos 往后查找字符串前 n 个字符第一次出现的位置int find(const char c, int pos = 0) const;
// 从索引为 pos 往后查找字符 c 第一次出现的位置int rfind(const string& s, int pos = npos) const;
// (逆序)从索引为 pos 往前查找字符串对象 s 第一次出现的位置int rfind(const char* s, int pos = npos) const;
// (逆序)从索引为 pos 往前查找字符串 s 第一次出现的位置int rfind(const char* s, int pos, int n) const;
// (逆序)从索引为 pos 往前查找字符串前 n 个字符第一次出现的位置int rfind(const char c, int pos = npos) const;
// (逆序)从索引为 pos 往前查找字符 c 第一次出现的位置
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("iloveyoubabyyoukonw!");
// 有参构造
string s2("ou");
// 初始化字符
string s3;
s3 = 'u';
// 正序查找
// 1. 从索引为 0 往后查找字符串对象 s2,返回第一次出现位置的索引
cout << s1.find(s2) << endl; // 6
// 2. 从索引为 0 往后查找字符串 "ou",返回第一次出现位置的索引
cout << s1.find("ou") << endl; // 6
// 3. 从索引为 0 往后查找字符串 "ou" 的前 1 个元素,返回第一次出现位置的索引
cout << s1.find("ou", 0, 1) << endl; // 2
// 4. 从索引为 0 往后查找字符 'v',返回第一次出现位置的索引
cout << s1.find('v') << endl; // 3
// 逆序查找
// 1. (逆序)从索引为 20 往前查找字符串对象 s2,返回第一次出现位置的索引
cout << s1.rfind(s2) << endl; // 13
// 2. (逆序)从索引为 20 往前查找字符串 "ou",返回第一次出现位置的索引
cout << s1.rfind("ou") << endl; // 13
// 3. (逆序)从索引为 20 往前查找字符串 "ou" 的前 1 个元素,返回第一次出现位置的索引
cout << s1.rfind("ou", 20, 1) << endl; // 16
// 4. (逆序)从索引为 20 往前查找字符 'v',返回第一次出现位置的索引
cout << s1.rfind('v') << endl; // 3
system("pause");
return 0;
}
- 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
字符串替换:在指定的位置替换字符串
string& replace(int pos, int n, const string &s);
// 从 pos 开始的 n 个字符替换为字符串对象 sstring& replace(int pos, int n, const char* s);
// 从 pos 开始的 n 个字符替换为字符串 s
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("loveyou");
// 有参构造
string s2("me");
// 1. 替换字符串对象 s2
s1.replace(4, 3, s2);
cout << s1 << endl; // loveme
// 2. 替换字符串
s1.replace(4, 2, "him");
cout << s1 << endl; // lovehim
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
string 比较
函数原型
int compare(const string &s) const;
// 与字符串对象 s 比较int compare(const char *s) const;
// 与字符串 s 比较
比较方式:根据字符的 ASCII 码;相等则返回 0;大于则返回 1;小于则返回 -1;
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("loveyou");
// 有参构造
string s2("me");
// 1. 与字符串对象比较
cout << s1.compare(s2) << endl; // -1
cout << s1.compare(s1) << endl; // 0
// 2. 与字符串对比
cout << s1.compare("loveyou") << endl; // 0
cout << s1.compare("loveyoue") << endl; // -1
cout << s1.compare("loveyo") << endl; // 1
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
string 字符存取
string 中单个字符存取方式有二种
char& operator[](int n);
// 通过索引取字符char& at(int n);
// 通过 at 方式取字符
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("loveyou");
// 第一种方式
for (int i = 0; i < s1.size(); i++) {
cout << s1[i] << " "; // l o v e y o u
}
cout << endl;
// 第二种方式
for (int j = 0; j < s1.size(); j++) {
cout << s1.at(j) << " "; // l o v e y o u
}
cout << endl;
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
string 插入和删除
函数原型
string& insert(int pos, const char* s);
// 插入字符串 sstring& insert(int pos, const string& s);
// 插入字符串对象 sstring& insert(int pos, int n, char c);
// 在指定位置插入 n 个字符 cstring& erase(int pos, int n);
// 删除从 pos 开始的 n 个字符
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("loveyou");
string s2("his");
// 1. 插入字符串
s1.insert(0, "me");
cout << s1 << endl; // meloveyou
// 2. 插入字符串对象
s1.insert(2, s2);
cout << s1 << endl; // mehisloveyou
// 3. 在指定位置插入 n 个字符
s1.insert(0, 3, 'a');
cout << s1 << endl; // aaamehisloveyou
// 4. 删除从 pos 开始的 n 个字符
s1.erase(0, 5);
cout << s1 << endl; // hisloveyou
system("pause");
return 0;
}
- 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
string 子串
函数原型
string substr(int pos, int n) const;
// 返回由 pos 开始的 n 个字符组成的字符串
#include <iostream>
using namespace std;
#include <string>
int main() {
// 有参构造
string s1("loveyou");
// 构造函数
string s2;
s2 = s1.substr(0, 3);
cout << s2 << endl; // lov
s2 = s1.substr(2, 4);
cout << s2 << endl; // veyo
system("pause");
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19