STL 是“Standard Template Library”的缩写,中文译为“标准模板库”。

1. Vector

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
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <vector> // 引入 vector 容器的支持

using namespace std;

int main() {
std::cout << "标准模板库" << std::endl;

vector<int> vector1;

vector<int> vector2(10); // 指定10的空间大小

vector<int> vector3(10, 0); // 有了10个值了 每个值都是0

vector<int> vector4;

// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面

// 插入数据
vector4.insert(vector4.begin(), 40);
vector4.insert(vector4.begin(), 60);
vector4.insert(vector4.begin(), 80);
vector4.insert(vector4.begin(), 100);
vector4.insert(vector4.begin(), 200);

// 第一个
cout << " 修改前:vector4.front():" << vector4.front() << endl;
vector4.front() = 99; // 默认修改第一个
cout << " 修改后:vector4.front():" << vector4.front() << endl;

// 最后一个
cout << " 修改前:vector4.back():" << vector4.back() << endl;
vector4.back() = 777; // 默认修改最后
cout << " 修改后:vector4.back():" << vector4.back() << endl;

vector4.erase(vector4.begin()); // 移除第一个元素(内部:通过迭代器的位置 进行移除) 删除

// 循环打印,默认 从大到小输出
for (int i = 0; i < vector4.size(); ++i) {
cout << "item:" << vector4[i] << endl;
}

// KT的类型推到 相当于 C++ auto
/*var a = 10;
var b = 30.4f;
var c = "";*/

// 迭代器 循环遍历
// auto Kotlin自带类型推到
// for (vector<int>::iterator iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
for (auto iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
// 迭代器 当中指针操作 iteratorVar++
cout << "迭代器:" << *iteratorVar << endl;
}

cout << "" << endl;

return 0;
}

2. 栈

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
#include <iostream>
#include <stack>
using namespace std;

int main() {
stack<int> stackVar;

// 压栈(注意:stack无法指定那个位置去压栈)
stackVar.push(30);
stackVar.push(60);
stackVar.push(90);

// 请问那个元素,在最上面(看图)

// [] 角标是不行的,内部没有重载此运算符
/*for (int i = 0; i < stackVar.size(); ++i) {
// cout << stackVar[i] << endl;
// cout << stackVar.at() << endl;
}*/

// 他根本就没有迭代器
// 开发者 自己组装 迭代器 遍历
/*for (stack<int>::iterator; i < ; ++i) {

}*/

// 慎用,为什么? 元素被弹完了
// 这种方式是可以的,手枪把子弹全部打完【会把元素清空】
while (!stackVar.empty()) {
int top = stackVar.top(); // top == 获取栈顶的元素
cout << "获取栈顶的元素:" << top << endl; // 永远拿 90

stackVar.pop(); // 把栈顶的元素 弹出去 【删除】
}

/*int top = stackVar.top();
cout << top << endl;*/

return 0;
}

3. 队列

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
#include <iostream>
#include <queue> // 队列支持(内部:基本上 链表 、 数组 )

// 容器 + 数据结构
// 音视频: 压缩格式音频数据(push) 保存 pop消费最前面的 音频格式数据 获取

using namespace std;

int main() {
queue<int> queueVar;

queueVar.push(20);
queueVar.push(40);
queueVar.push(60);

// 第一个元素是谁 20 FIFO 原则
cout << " 修改前: queueVar.front():" << queueVar.front() << endl;
queueVar.front() = 88;
cout << " 修改后: queueVar.front():" << queueVar.front() << endl;

// 最后一个
cout << " 修改前: queueVar.back():" << queueVar.back() << endl;
queueVar.back() = 88;
cout << " 修改后: queueVar.back():" << queueVar.back() << endl;

// 没有找到 角标
/*for (int i = 0; i < 9; ++i) {
queueVar[i];
}*/

// 他根本就没有迭代器
/*for (queue<int>::iterator; i < ; ++i) {

}*/

// 慎用,为什么? 前面的元素全部被消费完了
while (!queueVar.empty()) {
cout << "while1:" << queueVar.front() << endl;

queueVar.pop(); // 把前面的元素 给消费掉 【删除】
}

// 此处队列中元素已经被清空了
while (!queueVar.empty()) {
cout << "while2:" << queueVar.front() << endl;

queueVar.pop(); // 把前面的元素 给消费掉 【删除】
}

return 0;
}

4. 优先级队列

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
#include <iostream>
#include <queue>
using namespace std;

// priority_queue 内部对我们前面的vector 有一定的封装

// Deque 跟 queue 有什么区别啊 双端队列

int main() {
// 优先级队列,默认做了 从大到小 60 50 40 ...
// priority_queue<int> priorityQueue;

// 隐式代码: vector<int>, less<int>
// priority_queue<int, vector<int>, less<int>> priorityQueue;

// less
// less<int> return __x < __y; 上一个元素和当前元素 比较,返回ture false 从大到小

// less return __x < __y; // 从大到小
// greater return __x > __y; // 从小到大

// 第二个参数:他内部需要vector,你就给他
priority_queue<int ,vector<int>, less<int>> priorityQueue;
// priority_queue<int ,vector<int>, greater<int>> priorityQueue;

priorityQueue.push(10);
priorityQueue.push(20);
priorityQueue.push(30);
priorityQueue.push(40);
priorityQueue.push(50);
priorityQueue.push(60);

cout << priorityQueue.top() << endl; // 60

// 循环代码
while (!priorityQueue.empty()) {
cout << "while1:" << priorityQueue.top() << endl; // 一直是60
priorityQueue.pop(); // 最前面的元素消费掉
}
return 0;
}

5. List容器

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
// Java:ArrayList采用Object[]数组,   C++的list 内部:采用链表

#include <iostream>
#include <list> // list容器的支持
using namespace std;

int main() {
list<int> listVar;

// 插入操作
listVar.push_front(50); // 插入到前面 明确
listVar.push_back(60); // 插入到后面
listVar.insert(listVar.begin(), 70); // 插入到前面 灵活
listVar.insert(listVar.end(), 80); // 插入到后面

// 修改操作
listVar.back() = 88;
listVar.front() = 55;

// 删除
listVar.erase(listVar.begin()); // 删除最前面的 55
listVar.erase(listVar.end()); // 删除最后面的 88

// list 迭代器
// 不用通过角标去访问,也不能修改 遍历
for (list<int>::iterator it = listVar.begin(); it != listVar.end() ; it ++) {
cout << *it << endl;
}

return 0;
}

6. set容器

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
// set(内部:红黑树结构),会对你存入的数据进行排序,但是绝对不允许元素相同

#include <iostream>
#include <set>

using namespace std;


int main() {
set<int, less<int>> setVar; // __x < __y 从大到小,默认情况下 就是 less

// 添加参数,不需要用迭代器,也不需要指定位置
setVar.insert(1);
setVar.insert(3);
setVar.insert(2);
setVar.insert(4);

// 重复插入,并不会报错 std::pair<iterator, bool>
pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);

// res.first 获取第一个元素 迭代器 当前迭代器 最后一个位置
// res.second 获取第二个元素 bool
bool insert_success = res.second;
if (insert_success) {
cout << "恭喜你,插入成功" << endl;

// 插入成功后,我用第一个元素遍历
for (; res.first != setVar.end(); res.first ++) {
cout << *res.first << endl;
}

} else {
cout << "哎,插入失败.." << endl;
}

// 全部遍历 auto 自动推到
for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
cout << *it << endl;
}

return 0;
}

7. 函数谓词

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
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <set>

using namespace std;

// set(内部:红黑树结构),会对你存入的数据自动进行排序,但是绝对不允许元素相同

class Person {
public:
string name;
int id;
Person(string name, int id) : name(name), id(id) {}
};

// C++ 都是一些常规的 谓词 不能满足功能, 模仿C++源码的谓词 自定义谓词 解决这个问题

// C++缔造者写的这个源码 没有对象比较的功能 【系统源码谓词 做不到对象比较功能】
// bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }

// 我们就自定义这个功能 【自定义谓词 没有达到谓词的标准】
bool doCompareAction(const Person& person1, const Person& person2) {
return person1.id < person2.id;
};

// 真正的谓词
struct doCompareAction2 {
public:
bool operator() (const Person& __x, const Person& __y) {
return __x.id < __y.id;
}
};

// class doCompareAction3也是可以的
struct doCompareAction3 {
public:
bool operator() (const Person& __x, const Person& __y) {
return __x.id > __y.id;
}
};

int main() {
// 默认是 less return 对象1 < 对象2;

set<Person, doCompareAction2> setVar;

// set<Person, doCompareAction3> setVar;

// 构建对象
Person p1 ("Snake", 1);
Person p2 ("kevin", 2);
Person p3 ("Jack", 3);

// 把构建的对象 插入到 set 容器里面去
setVar.insert(p1);
setVar.insert(p2);
setVar.insert(p3);

// name string --- c_str() ----> char *
for (set<Person>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
cout << it->name.c_str() << " , " << it->id << endl;
}

return 0;
}

8. Map 与 multimap

  • map中insert()插入之后会对key进行排序,key不能重复,如果采用覆盖的方式插入值,使用arr[]方式
  • multimap中key可以重复
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
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <map>

using namespace std;

int main() {

// 注意:map会对key进行排序,默认 key不能重复
map<int, string> mapVar;

// TODO 添加数据
// 第一种方式
mapVar.insert(pair<int, string>(1, "一"));

// 第二种方式
mapVar.insert(make_pair(2, "二"));

// 第三种方式
mapVar.insert(map<int, string>::value_type (3, "三"));

// 上面三种方式 key不能重复
// 思考:既然会对key进行排序,那么key是不能重复的(会插入失败)
mapVar.insert(pair<int, string>(3, "三3"));

// 第四种方式:key可以重复,相当于覆盖 mapVar[key]=Value
mapVar[4] = "四";
mapVar[4] = "肆"; // 第四种方式覆盖/替换(常用)

/**
* typedef typename _Rep_type::iterator iterator; 之前常规的迭代器
typedef typename _Rep_type::const_iterator const_iterator; 只读的,只能读,不能修改 的迭代器
typedef typename _Rep_type::reverse_iterator reverse_iterator; 倒序打印的迭代器
*/

// 循环打印,迭代器
for (map<int, string>::iterator it = mapVar.begin() ; it != mapVar.end() ; it ++) {
cout << it->first << "," << it->second.c_str() << "\t";
}
cout << endl;

// Jack想知道,怎么判断插入成功、失败
std::pair<map<int, string>::iterator, bool> result = mapVar.insert(map<int, string>::value_type (6, "66三san"));
if (result.second) {
cout << "插入成功" << endl;
} else {
cout << "插入失败" << endl;
}
// 我想知道插入后的 数据
for (result.first == mapVar.begin(); result.first != mapVar.end() ; result.first++) {
cout << result.first->first << " , " << result.first->second << endl;
}

// 查找,操作
map<int, string> ::iterator findResult = mapVar.find(3); // 查找
if (findResult != mapVar.end()) {
cout << "恭喜,找到了" << findResult->first << "," << findResult->second.c_str() << endl;
} else {
cout << "不恭喜,没找到了" << endl;
}

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
52
53
54
// multimap 主要使用他的分组特性
#include <iostream>
#include <map>

using namespace std;

int main() {
// 1.key可以重复, 2.key重复的数据可以分组, 3.key会排序, 4.value不会排序
multimap<int, string> multimapVar;

multimapVar.insert(make_pair(10, "十个1"));
multimapVar.insert(make_pair(10, "十个2"));
multimapVar.insert(make_pair(10, "十个3"));

multimapVar.insert(make_pair(30, "三十1"));
multimapVar.insert(make_pair(30, "三十3"));
multimapVar.insert(make_pair(30, "三十2"));


multimapVar.insert(make_pair(20, "二十1"));
multimapVar.insert(make_pair(20, "二十2"));
multimapVar.insert(make_pair(20, "二十3"));

for (auto iteratorVar = multimapVar.begin(); iteratorVar != multimapVar.end() ; iteratorVar ++) {
cout << iteratorVar->first << "," << iteratorVar->second << endl;
}
cout << endl;

// TODO 核心功能是分组
int result;
cout << "请输入你要查询的key,为int类型:" << endl;
cin >> result;

multimap<int, string>::iterator iteratorVar = multimapVar.find(result);
while (iteratorVar != multimapVar.end()) {
cout << iteratorVar->first << "," << iteratorVar->second << endl;

if (iteratorVar->first != result) {
break;; // 循环结束
}

// 严谨性
if (iteratorVar == multimapVar.end()) {
break; // 循环结束
}

// 此处写匹配到的逻辑

// 需要自己做逻辑控制,不然死循环了
iteratorVar++;
}

return 0;
}

9. 一元谓词(仿函数)

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
#include <iostream>
#include <set> // STL包
#include <algorithm> // 算法包

using namespace std;

// 谓词相当于仿函数
// 通常叫法叫仿函数

// TODO 第一版: 为什么叫仿函数 (空谓词 一元谓词 二元谓词 三元谓词)
class ComPareObject {
public:
// void operator()(int id) {} 一元谓词
// void operator()(int id,string name) {} 二元谓词
void operator()() { // 重装了括号运算符
cout << "仿函数" << endl;
}
};

// 普通函数
void fun2() {
cout << "普通函数" << endl;
}

int main() {
ComPareObject fun1;

// 非常像函数的调用,很像函数 = (仿函数)
fun1();

fun2();

return 0;
}

10. 引入算法包

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
#include <iostream>
#include <set> // STL包
#include <algorithm> // 算法包

using namespace std;

// 我如何阅读C++源码,来写我们的仿函数
// 明明白白的仿函数(一元谓词==一元函数对象)
class showActionObj {
public:
void operator()(int content) {
cout << "自定义仿函数" << content << endl;
}
};

// 简洁方式(回调函数、一元谓词 但是不能称为 仿函数)
void showAction(int content) {
cout << "自定义 一元谓词" << content << endl;
}

using namespace std;

int main() {
set<int> setVar;

setVar.insert(10);
setVar.insert(20);
setVar.insert(30);
setVar.insert(40);
setVar.insert(50);
setVar.insert(60);

// 调用一元谓词,注意:有括号
// for_each(setVar.begin(), setVar.end(), showActionObj());

// 调用回调函数
for_each(setVar.begin(), setVar.end(), showAction);

return 0;
}

11. 仿函数

回调函数扩展性不高,一般用于简单逻辑,写法也比较简单;仿函数扩展性更强,写法稍微复杂一点。

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
#include <iostream>
#include <set> // STL包
#include <algorithm> // 算法包

using namespace std;

// 回调函数 (功能够简单)
void showAction(int __first) {
cout << "一元谓词" << __first << endl;
}

// 仿函数(扩展性强) C++内置源码使用仿函数频率高,扩展性强
class showActionObj {
public:
int count = 0;
void _count() { cout << "本次输出次数是:" << this->count << endl; }

void operator() (int __first) {
cout << "仿函数" << __first << endl;
count++;
}
};

int main() {
// 理解:类型传递
// set<int, showActionObj> setVar; 这样写的语法是OK的,不能加括号
set<int> setVar;

setVar.insert(10);
setVar.insert(20);
setVar.insert(30);

// TODO 第一种方式
for_each(setVar.begin(), setVar.end(), showAction);
// 请你统计打印次数? 答:做不到

// TODO 第二种方式
// 此处s相当于showActionObj()
showActionObj s; // 理解:值传递
// for_each第三个参数传入s,会拷贝一个副本,运算结束需要接收回来。
s = for_each(setVar.begin(), setVar.end(), s); // 传入进去的s是新的副本,我们外面的s是旧地址
// 请你统计打印次数? 答:OK
s._count();

return 0;
}

12. 对象生命周期

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
52
53
54
55
#include <iostream>
#include <set> // set 存入对象 奔溃(set会自动排序,对象没法排序,所以奔溃) 解决方案:自定义仿函数解决
#include <vector> // 存入对象

using namespace std;

class Person {
private:
string name;
public:
Person(string name) : name(name) {}

void setName(string name) {
this->name = name;
}

string getName() {
return this->name;
}

Person(const Person &person) {
this->name = person.name; // 浅拷贝

cout << "Person拷贝构造函数执行了..." << endl;
}

~Person() {
cout << "Person析构函数执行了" << endl;
}
};

int main() {
// Java:把对象存入 添加到 集合
// C++: 调用拷贝构造函数,存进去的是另一个新的对象

vector<Person> vectorVar;

// person 被main函数弹栈 析构一次
Person person("Jack"); // 2 Jack

// 里面的insert函数弹栈 析构一次
vectorVar.insert(vectorVar.begin(), person); // 外面的person是旧地址,到insert函数里面的person就是新地址(拷贝构造函数 一次)

person.setName("Kevin"); // 1

// newPerson 被main函数弹栈 析构一次
Person newPerson =
vectorVar.front(); // front里面的person是旧地址, 外面的newPerson就是新地址(拷贝构造函数 一次)

cout << "newPerson:" << newPerson.getName().c_str() << endl;

// 3次析构函数 两次拷贝构造

return 0;
} // main弹栈

13. 预定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <set> // STL包
#include <algorithm> // 算法包
using namespace std;

int main() {
// "Jack" + "AAAA" // 运算符重载

// C++已经提供了 预定义函数 plus,minus,multiplies,divides,modulus ...
plus<int> add_func;

int r = add_func(1, 1);
cout << r << endl;

plus<string> add_func2;
string r2 = add_func2("AAAA", "BBB");
cout << r2 << endl;

plus<float> add_func3;
float r3 = add_func3(4354.45f, 34.3f);
cout << r3 << endl;

return 0;
}

14. 手写预定义函数

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
#include <iostream>
#include <set> // STL包
#include <algorithm> // 算法包
using namespace std;

template<typename Arg1, typename Arg2, typename Result>
struct binary_function
{
/// 第一个参数类型 是底一个参数的类型
typedef Arg1 first_argument_type;

//econd_argument_type是第二个参数的类型
typedef Arg2 second_argument_type;

/// @c result_type是返回类型
typedef Result result_type;
};

// TODO 对象 + 对象
// 1.运算符重载
// 2.对象+对象 自己去写仿函数

template<typename T>
struct plus_d /*: public binary_function<T, T, T>*/
{
T operator() (const T & x, const T & y) {
return x + y;
}
};

int main() {

plus_d<int> add_func;
int r = add_func(1, 1);
cout << r << endl;

plus_d<string> add_func2;
string r2 = add_func2("AAAA", "BBB");
cout << r2 << endl;

plus_d<float> add_func3;
float r3 = add_func3(4354.45f, 34.3f);
cout << r3 << endl;

return 0;
}