STL基本概念

  • STL(Standard Template Library,标准模板库)
  • STL从广义上分为:容器(container)、算法(algorithm)、迭代器(iterator)
  • 容器和算法之间通过迭代器进行无缝连接
  • STL几乎所有的代码都采用了模板类或者模板函数

STL六大组件

STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  1. 容器:各种数据结构,如VectorListDequeSetMap等,用来存放数据
  2. 算法:各种常用的算法,如SortFindCopyFor_Each
  3. 迭代器:扮演了容器与算法之间的胶合剂
  4. 仿函数:行为类似函数,可作为算法的某种策略
  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
  6. 空间配置器:负责空间的配置与管理

STL中容器、算法、迭代器

容器

STL容器就是将运用最广泛的一些数据结构实现出来

常用的数据结构:数组、链表、数、栈、队列、集合、映射表等

这些容器分为序列式容器和关联式容器两种:

  • 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
  • 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

算法

有限的步骤,解决逻辑或数学上的问题,这一门学科称为算法(Algorithms)

算法分为:质变算法和非质变算法

  • 质变算法:是指运算过程中会更改区间内的元素内容。例如拷贝、替换、删除等等
  • 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等

迭代器

提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式

每个容器都有自己专属的迭代器

迭代器使用非常类似于指针,初次接触可以将其先理解为指针

迭代器种类:

种类 功能 支持运算
输入迭代器 对数据的只读访问 只读,支持++、==、!=
输出迭代器 对数据的只写访问 只写,支持++
前向迭代器 读写操作,并能向前推进迭代器 读写,支持++、==、!=
双向迭代器 读写操作,并能向前和向后操作 读写,支持++、–
随机访问迭代器 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 读写,支持++、–、[n]、-n、<、<=、>、>=

常用的容器中迭代器种类为双向迭代器和随机访问迭代器

STL容器

String容器

本质:

  • string是C++风格的字符串,而string本质上是一个类

string和char 区别:*

  • char * 是一个指针
  • string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器

特点:

string类内部封装了很多成员方法

例如:查找find拷贝copy删除delete替换replate插入insert

string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责

string构造函数

构造函数原型:

  • string(); // 创建一个空的字符串,例如:string str;
  • string(const char* s); // 使用字符串s初始化
  • string(const string& str); // 使用一个string对象初始化另一个string对象
  • string(int n,char c); // 使用n个字符c初始化

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main() {
const char* c = "aaa";
string s(c);
cout << s << endl; // aaa

string s2 = "bbb";
string s3(s2);
cout << s3 << endl; // bbb

string s4(3, 'c');
cout << s4 << endl; // ccc

return 0;
}

string赋值操作

功能描述:

  • 给string字符串进行赋值

赋值的函数原型:

  • string& operator=(const char* s); // char*类型字符串 赋值给当前的字符串

  • 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赋给当前字符串

示例:

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
int main() {
string s1 = "Hello S1";
cout << s1 << endl; // Hello S1

string tmp = "Hello S2";
string s2 = tmp;
cout << s2 << endl; // Hello S2

string s3; // string s3 = 'a'; 会报错
s3 = 'a';
cout << s3 << endl; // a

string s4;
s4.assign("Hello S4");
cout << s4 << endl; // Hello S4

string s5;
s5.assign("Hello S5 S5 S5", 8);
cout << s5 << endl; // Hello S5

string str = "Hello S6";
string s6;
s6.assign(str);
cout << s6 << endl; // Hello S6

string s7;
s7.assign(5,'7');
cout << s7 << endl; // 77777

return 0;
}

string字符串拼接

功能描述:

  • 实现在字符串末尾拼接字符串

函数原型:

  • string& operator+=(const char* str); // 重载+=操作符
  • string& operator+=(const char c); // 重载+=操作符
  • string& operator+=(const string& str); // 重载+=操作符
  • string& append(const char* s); // 把字符串s连接到当前字符串的末尾
  • string& append(const char* s,int n); // 把字符串s的前n个字符连接到当前字符串的末尾
  • string& append(const string& s); // 同operator+=(const string& str)
  • string& append(const string& s,int pos,int n); // 字符串s中从pos开始的n个字符连接到当前字符串的末尾

示例:

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
int main() {
string s1 = "hello";
s1 += " s1";
cout << s1 << endl; // hello s1

string s2 = "hello";
s2 += '1';
cout << s2 << endl; // hello1

string s3 = "hello";
s3.append(" s3");
cout << s3 << endl; // hello s3

string s4 = "hello";
s4.append(" s4s4s4s4", 3);
cout << s4 << endl; // hello s4

string s5 = "hello";
s5.append(s5);
cout << s5 << endl; // hellohello

string s6 = "hello";
s6.append("123s7321", 3, 2);
cout << s6 << endl; // hellos7

return 0;
}

string查找和替换

功能描述:

  • 查找:查找指定字符串是否存在
  • 替换:在指定的位置替换字符串

函数原型:

  • int find(const string& str,int pos = 0) const; // 查找str第一次出现位置,从pos开始查找
  • int find(const char* s,int pos = 0) const; // 查找s第一次出现位置,从pos开始查找
  • int find(const char* s,int pos,int n) const; // 从pos位置查找s的前n个字符第一次位置
  • int find(const char c,int pos = 0) const; // 查找字符c第一次出现的位置,从pos开始查找
  • int rfind(const string& str,int pos = 0) const; // 查找str最后一次位置,从pos开始查找
  • int rfind(const char* s,int pos = npos) const; // 查找s最后一次出现位置,从pos开始查找
  • int rfind(const char* s,int pos,int n) const; // 从pos查找s的前n个字符最后一次位置
  • int rfind(cosnt char c,int pos = 0) const; // 查早字符c最后一次出现位置,从pos开始查找
  • string& replace(int pos,int n,const string& str); // 替换从pos开始的n个字符为str
  • string& replace(int pos,int n,const char* s); // 替换从pos开始的n个字符为字符串s

示例:

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
int main() {
string str = "hello world";


int f1 = str.find("or");
cout << f1 << endl; // 7

int f2 = str.find("d");
cout << f2 << endl; // 10

int f3 = str.find("lol", 0, 2);
cout << f3 << endl; // 3

int f4 = str.find('h');
cout << f4 << endl; // 0

int f5 = str.rfind("l");
cout << f5 << endl; // 9

int f6 = str.rfind("r", 10);
cout << f6 << endl; // 8

int f7 = str.rfind("lold", 10, 2);
cout << f7 << endl; // 3

int f8 = str.rfind('o', 10);
cout << f8 << endl; // 7

string tmp = "s1s1";
string s1 = str.replace(6, 2, tmp);
cout << s1 << endl; // hello s1s1rld

const char* c = "s2s2";
string s2 = str.replace(6, 2, c);
cout << s2 << endl; // hello s2s2s1rld 注意replace会对源数据进行修改

return 0;
}

string字符串比较

功能描述:

  • 字符串之间的比较

比较方式:

  • 字符串比较是按字符的ASCII码进行对比
  • 从第一个字符开始依次比较每个字符的 ASCII 值,直到找到不同的字符为止
  • 长度不等 → 较长的字符串更大

比较结果:

= 返回 0

> 返回 1

< 返回 -1

函数原型:

  • int compare(const string& s) const;
  • int compare(const char* s) const;

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main() {
string str = "abc";

int c1 = str.compare("abc");
int c2 = str.compare("abcd");
int c3 = str.compare("ab");
int c4 = str.compare("aaa");
int c5 = str.compare("ccc");

cout << c1 << endl;
cout << c2 << endl;
cout << c3 << endl;
cout << c4 << endl;
cout << c5 << endl;

return 0;
}

string字符存取

string中单个字符存取方式有两种:

  • char& operator[](int n); // 通过[]方式获取字符
  • char& at(int n); // 通过at方式获取字符

示例:

1
2
3
4
5
6
7
8
9
10
11
int main() {
string str = "hello world";

char c1 = str[4];
cout << c1 << endl; // o

char c2 = str.at(4);
cout << c2 << endl; // o

return 0;
}

string插入和删除

功能描述:

  • 对string字符串进行插入和删除字符操作

函数原型:

  • string& insert(int pos,const char* s); // 插入字符串
  • string& insert(int pos,const string& str); // 插入字符串
  • string& insert(int pos,int n,char c); // 在指定位置插入n个字符c
  • string& erase(int pos, int n = npos); // 删除从Pos开始的n个字符

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main() {
string str = "hello world";
str.insert(str.begin(), 'a');
cout << str << endl; // ahello world

str = "hello world";
str.insert(0, "hello");
cout << str << endl; // hellohello world

str = "hello world";
str.insert(0, 3, 'a');
cout << str << endl; // aaahello world

str = "hello world";
str.erase(0,6);
cout << str << endl; // world

return 0;
}

string子串

功能描述:

  • 从字符串中获取想要的子串

函数原型:

  • string substr(int pos = 0,int n = npos) const; // 返回由pos开始的n个字符组成的字符串

示例:

1
2
3
4
5
6
7
int main() {
string str = "ABCDEFGHIJK";
string substr = str.substr(0, 3);
cout << substr << endl;

return 0;
}

Vector容器

STL中最常用的容器为Vector,可以理解为数组

存放内置数据类型并遍历

容器:vector

算法:for_each

迭代器:vector<int>::iterator

示例:

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 <string>
#include <vector>
#include <algorithm>

using namespace std;

void print(int val) {
cout << val << " ";
}

void test01() {
// 创建数组容器
vector<int> v;

// 像容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);

// 通过迭代器遍历数组
vector<int>::iterator itBegin = v.begin(); // 起始迭代器,指向容器的第一个元素
vector<int>::iterator itEnd = v.end(); // 结束迭代器,指向容器最后一个元素的下一个位置

// 第一种遍历方式,迭代器++
while (itBegin != itEnd) {
cout << *itBegin << " ";
itBegin++;
}

cout << endl;

// 第二种遍历方式,利用for循环+迭代器
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}

cout << endl;

// 第三种遍历方式,利用容器提供的方法
for_each(v.begin(), v.end(), print); // 第三个参数是一个函数,用于实现打印逻辑的
}

int main() {
test01();


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
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Person {
public:
string name;
int age;

Person(string name, int age) {
this->name = name;
this->age = age;
}
};

void test01() {
vector<Person> v;

// 向容器中添加数据
for (int i = 0; i < 10; i++) {
Person p("person" + to_string(i), i);
v.push_back(p);
}

// 遍历容器
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
cout << "name: " << it->name << " age: " << it->age << endl;
}
}

void test02() {
vector<Person*> v;

// 向容器中添加数据
for (int i = 0; i < 10; i++) {
Person *p = new Person("person" + to_string(i), i);
v.push_back(p);
}

// 遍历容器
for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
cout << "name: " << (*it)->name << " age: " << (*it)->age << endl;
}

// 释放堆区内数据
for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
delete *it;
}

v.clear(); // 清空指针(避免野指针)
}



int main() {
// test01();

test02();

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;


void test01() {
vector<vector<int>> v;

// 为内层vector赋值并添加到外层vector中
for (int i = 0; i < 10; i++) {
vector<int> v1;
for (int j = 0; j < 10; j++) {
v1.push_back(j);
}
v.push_back(v1);
}

for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) {
cout << "第" << it - v.begin() << "行:" << endl;
for (vector<int>::iterator it2 = it->begin(); it2 != it->end(); it2++) {
cout << *it2 << " ";
}
cout << endl;
}
}

int main() {
test01();

/*
第0行:
0 1 2 3 4 5 6 7 8 9
第1行:
0 1 2 3 4 5 6 7 8 9
第2行:
0 1 2 3 4 5 6 7 8 9
...
*/
return 0;
}

vector基本概念

功能:

  • vector数据结构和数组非常相似,也称为单端数组

vector与普通数组区别:

  • 不同之处在于数组是静态空间,而vector可以动态扩展

动态扩展:

  • 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新数据,释放原空间
clip_image002
  • vector容器的迭代器是支持随机访问的迭代器

vector构造函数

功能描述:

  • 创建vector容器

函数原型:

  • vector<T\> v; // 采用模板实现类实现,默认构造函数
  • vector(v.begin(), v.end()); // 将v[begin(), end())区间中的元素拷贝给本身
  • vector(n, elem); // 构造函数将n个elem拷贝给本身
  • vector(const vector &vec); // 拷贝构造函数

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;


// 打印Vector容器元素模板函数
template <class T>
void printVec(vector<T> &v) {
for (class vector<T>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}

void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
}

// 通过第二种方式创建vector
vector<int> v2(v1.begin(), v1.end());
printVec(v2);
}

void test02() {
// 通过第三种方式创建vector
vector<int> v1(10, 100);
cout << "v1:";
printVec(v1);

// 拷贝构造函数创建vector
vector<int> v2(v1);
cout << "v2:";
printVec(v2);
}

int main() {

// test01();

test02();
return 0;
}

vector赋值操作

功能描述:

  • 给vector容器进行赋值

函数原型:

  • vector& operator=(const vector& vec); // 重载等号操作符
  • assign(beg, end); // 将[beg,end)区间中的数据拷贝赋值给本身
  • assign(n,elem); // 将n个elem拷贝赋值给本身

示例:

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 <string>
#include <vector>
#include <algorithm>

using namespace std;

// 打印Vector容器元素模板函数
template <typename T>
void printVec(vector<T>& vec) {
for (typename vector<T>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << " ";
}

cout << endl;
}

void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}

// 第一种方式赋值
vector<int> v2 = v1;
printVec(v2);
}

void test02() {
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}

// 第二种方式赋值
vector<int> v2;
v2.assign(v1.begin(), v1.end());
printVec(v2);
}

void test03() {
// 第三种方式赋值
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}

v1.assign(10, 100);
printVec(v1);
}

int main() {
cout << "------test01------" << endl;
test01();
cout << "------test02------" << endl;
test02();
cout << "------test03------" << endl;
test03();

return 0;
}

vector容量和大小

功能描述:

  • 对vector容器的容量和大小操作

函数原型:

  • empty(); // 判断容器是否为空
  • capacity(); // 容器的容量
  • size(); // 返回容器中元素的个数
  • resize(int num); // 重新指定容器的长度,若容器变长,则以默认值填充新位置
    // 若容器变短,则末尾超出容器长度的元素被删除
  • reize(int num, elem); // 重新指定容器的长度,若容器变长,则以elem值填充新位置
    // 若容器变短,则末尾超出容器长度的元素被删除

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// 打印Vector容器元素模板函数
template <typename T>
void printVec(vector<T>& vec) {
for (typename vector<T>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << " ";
}

cout << endl;
}

void test01() {
vector<int> v1;
v1.empty() ? cout << "v1为空" << endl : cout << "v1不为空" << endl;

for (int i = 0; i < 10; i++) {
v1.push_back(i);
}

cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
cout << "原始v1内容为: ";
printVec(v1);

// 改变大小,并以默认值填充
cout << "改变大小为15,并填充默认值:" << endl;
v1.resize(15);
printVec(v1);

// 改变大小,并以指定值填充
cout << "改变大小为20,并填充100:" << endl;
v1.resize(20, 100);
printVec(v1);

// 改变大小,并删除过长元素
cout << "改变大小为5:";
v1.resize(5);
printVec(v1);
}


int main() {
test01();

return 0;
}

注意:这里v1的容量根据不同的编译器显示不同结果,但是都会比size的大小大一些,是因为编译器会自动为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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// 打印Vector容器元素模板函数
template <typename T>
void printVec(vector<T>& vec) {
for (typename vector<T>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << " ";
}

cout << endl;
}

void test01() {
vector<int> v1;

for (int i = 0; i < 10; i++) {
v1.push_back(i);
cout << "size: " << v1.size() << " capacity: " << v1.capacity() << endl;
}

/*
size: 1 capacity: 1
size: 2 capacity: 2
size: 3 capacity: 3
size: 4 capacity: 4
size: 5 capacity: 6
size: 6 capacity: 6
size: 7 capacity: 9
size: 8 capacity: 9
size: 9 capacity: 9
size: 10 capacity: 13
*/
}


int main() {
test01();

return 0;
}

vector插入和删除

功能描述:

  • 对vector容器进行插入、删除操作

函数原型:

  • push_back(ele); // 尾部插入元素ele
  • pop_back(); // 删除最后一个元素
  • insert(const_iterator pos, ele); // 迭代器指向位置pos前插入元素ele
  • insert(const_iterator pos, int count, ele); // 迭代器指向位置pos前插入count个元素ele
  • erase(const_iterator pos); // 删除迭代器指向的元素
  • erase(const_iterator start, const_iterator end); // 删除迭代器区间[start, end)的元素
  • clear(); // 清空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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// 打印Vector容器元素模板函数
template <typename T>
void printVec(vector<T>& vec) {
for (typename vector<T>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << " ";
}

cout << endl;
}

void test01() {
vector<int> v1;
for (int i = 0; i < 11; i++)
{
v1.push_back(i);
}
printVec(v1); // [0,1,2,3,4,5,6,7,8,9,10]

v1.pop_back();
printVec(v1); // [0,1,2,3,4,5,6,7,8,9]

vector<int>::iterator it = v1.begin();
v1.insert(it + 5, 100);
printVec(v1); // [0,1,2,3,4,100,5,6,7,8,9]

v1.insert(it + 9, 2, 200);
printVec(v1); // [0,1,2,3,4,100,5,6,7,200,200,8,9]

v1.erase(it + 5);
printVec(v1); // [0,1,2,3,4,5,6,7,200,200,8,9]

v1.erase(it + 8, it + 10);
printVec(v1); // [0,1,2,3,4,5,6,7,8,9]

v1.clear();
v1.empty() ? cout << "空" << endl : cout << "非空" << endl; // 空
}



int main() {
test01();

return 0;
}

注意:erase方法和clear方法不能释放堆区内存,如果在vector容器中开辟了堆区的数据,一定要通过循环+delete的方式清除,否则会造成内存泄漏

vector数据存取

功能描述:

  • 对vector中的数据的存取操作

函数原型:

  • at(int idx); // 返回索引idx所指的数据
  • operator[]; // 返回索引idx所指的数据
  • front(); // 返回容器中第一个数据元素
  • back(); // 返回容器中最后一个数据元素

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;


void test01() {
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i + 10);
}

cout << v.at(2) << endl; // 12
cout << v[3] << endl; // 13
cout << v.front() << endl; // 10
cout << v.back() << endl; // 19

v[3] = 100;
cout << v[3] << endl;

v.at(5) = 200;
cout << v.at(5) << endl;
}




int main() {
test01();

return 0;
}

vector互换容器

功能描述:

  • 实现两个容器内元素进行互换

函数原型:

  • swap(vec); // 将vec与本身的元素交换

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

// 打印Vector容器元素模板函数
template <typename T>
void printVec(vector<T>& vec) {
for (typename vector<T>::iterator it = vec.begin(); it != vec.end(); it++) {
cout << *it << " ";
}

cout << endl;
}


void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i + 1);
}

vector<int> v2;
for (int i = 10; i != 0; i--)
{
v2.push_back(i);
}

cout << "v1:" << endl;
printVec(v1); // 1 2 3 4 5 6 7 8 9 10

cout << "v2:" << endl;
printVec(v2); // 10 9 8 7 6 5 4 3 2 1

v1.swap(v2);
cout << "v1和v2交换后:" << endl;

cout << "v1:" << endl;
printVec(v1); // 10 9 8 7 6 5 4 3 2 1

cout << "v2:" << endl;
printVec(v2); // 1 2 3 4 5 6 7 8 9 10
}




int main() {
test01();

return 0;
}

vector预留空间

功能描述:

  • 较少vector在动态扩展容量时的扩展次数

函数原型:

  • reserve(int len); // 容量预留len个元素长度,预留位置不初始化,元素不可访问

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

void test01() {
vector<int> v1;
v1.reserve(2000);
for (int i = 0; i < 10; i++)
{
v1.push_back(i + 1);
}

cout << "size:" << v1.size() << " capacity:" << v1.capacity() << endl; // size:10 capacity:2000

for (int i = 10; i < 2100; i++)
{
v1.push_back(i + 1);
}

cout << "size:" << v1.size() << " capacity:" << v1.capacity() << endl; // size:2100 capacity:3000(这里的3000容量是通过动态扩容机制实现的)
}




int main() {
test01();

return 0;
}

预留空间的作用是为了避免编译器多次的使用动态扩容。

动态扩容:每当数据超过容器的容量时,就会执行一次扩容(一般为1.5倍或2倍,主要依据编译器的区别),所以数据量变大时,就会频繁的扩容,影响性能。

deque容器

deque容器基本概念

功能:

  • 双端数组,可以对头端进行插入和删除

deque与vector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低
  • deque相对而言,对头部的插入删除速度会比vector快
  • vector访问元素时的速度会比deque快,这和两者内部实现有关

clip_image002-1547547642923

deque内部工作原理:

deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

clip_image002-1547547896341

  • deque容器的迭代器也是支持随机访问的

deque构造函数

功能描述:

  • deque容器构造

函数原型:

  • deque<T> deqT; // 默认构造形式
  • deque(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给deque
  • deque(n, elem); // 构造函数将n个elem拷贝给本身
  • deque(const deque &deq); // 拷贝构造函数

示例:

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 <string>
#include <deque>
#include <algorithm>

using namespace std;

// 打印deque容器模板函数
template <typename T>
void PrintDeque(const deque<T>& deq) {
// deque遍历与vector一样
for (typename deque<T>::const_iterator it = deq.begin(); it != deq.end(); it++) { // const_iterator是为了与形参匹配
cout << *it << " ";
}
cout << endl;
}

void test01() {
// deque<T> deqT
deque<int> deqInt1;
for (int i = 1; i < 11; i++)
{
deqInt1.push_back(i);
}


PrintDeque(deqInt1);

// deque(beg, end)
deque<int> deqInt2(deqInt1.begin(), deqInt1.end());
PrintDeque(deqInt2);

// deque(n, elem)
deque<int> deqInt3(10,101);
PrintDeque(deqInt3);

// deque(const deque deque&)
deque<int> deqInt4(deqInt3);
PrintDeque(deqInt4);
}

int main() {
test01();

return 0;
}

deque赋值操作

功能描述:

  • 给deque容器进行操作

函数原型:

  • deque& operator=(const deque &deq) // 重载等号操作符
  • assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身
  • assign(n, elem); // 将n个elem拷贝赋值给本身

示例:

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
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>

using namespace std;

template <typename T>
void PrintDeque(const deque<T> deq) {
for (typename deque<T>::const_iterator it = deq.begin(); it != deq.end(); it++) {
cout << *it << " ";
}
cout << endl;
}

void test01() {
deque<int> d1;
for (int i = 0; i < 10; i++) {
d1.push_back(i);
}

// deque& operator=(const deque& deq);
deque<int> d2 = d1;
cout << "d2: ";
PrintDeque(d2);

// assign(beg, end);
deque<int> d3;
d3.assign(d2.begin(), d2.end());
cout << "d3: ";
PrintDeque(d3);

// assign(n, elem);
deque<int> d4;
d4.assign(10, 100);
cout << "d4: ";
PrintDeque(d4);
}


int main() {
test01();

return 0;
}

deque大小操作

功能描述:

  • 对deque容器的大小进行操作

函数原型:

  • deque.empty(); //判断容器是否为空

  • deque.size(); //返回容器中元素的个数

  • deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    ​ //如果容器变短,则末尾超出容器长度的元素被删除。

  • deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

    ​ //如果容器变短,则末尾超出容器长度的元素被删除。

示例:

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
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>

using namespace std;

template <typename T>
void PrintDeque(const deque<T> deq) {
for (typename deque<T>::const_iterator it = deq.begin(); it != deq.end(); it++) {
cout << *it << " ";
}
cout << endl;
}

void test01() {
deque<int> deq1;

deq1.empty() ? cout << "deq1 is empty" << endl : cout << "deq1 is not empty" << endl; // deq1 is empty

for (int i = 0; i < 10; i++)
{
deq1.push_back(i+1);
}

cout << "deq1 size :" << deq1.size() << endl; // deq1 size :10

deq1.resize(5);
cout << "deq1 size :" << deq1.size() << endl; // deq1 size :5
PrintDeque(deq1); // 1 2 3 4 5

deq1.resize(15,404);
cout << "deq1 size :" << deq1.size() << endl; // deq1 size :15
PrintDeque(deq1); // 1 2 3 4 5 404 404 404 404 404 404 404 404 404 404
}


int main() {
test01();

return 0;
}

值得注意的是,deque相较于vector少了一个capacity()方法

capacity() 的设计初衷是反映连续内存的可用空间,而 deque 的内存结构无法用单一数值准确描述

deque插入和删除

功能描述:

  • 向deque容器中插入和删除数据

函数原型:

两端插入操作:

  • push_back(elem); //在容器尾部添加一个数据
  • push_front(elem); //在容器头部插入一个数据
  • pop_back(); //删除容器最后一个数据
  • pop_front(); //删除容器第一个数据

指定位置操作:

  • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置

  • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值

  • insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值

  • clear(); //清空容器的所有数据

  • erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置

  • erase(pos); //删除pos位置的数据,返回下一个数据的位置

示例:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>

using namespace std;

template <typename T>
void PrintDeque(const deque<T> deq) {
for (typename deque<T>::const_iterator it = deq.begin(); it != deq.end(); it++) {
cout << *it << " ";
}
cout << endl;
}

void test01() {
deque<int> d1;
d1.push_back(10);
d1.push_front(20);
PrintDeque(d1); // 20 10
}


void test02() {
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}

PrintDeque(d1); // 0 1 2 3 4 5 6 7 8 9

cout << "pop_back" << endl; // 0 1 2 3 4 5 6 7 8
d1.pop_back();
PrintDeque(d1);

cout << "pop_front" << endl; // 1 2 3 4 5 6 7 8
d1.pop_front();
PrintDeque(d1);
}

void test03() {
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
PrintDeque(d1); // 0 1 2 3 4 5 6 7 8 9

deque<int>::iterator it = d1.insert(d1.begin() + 5, 101);
PrintDeque(d1);
cout << "it = " << *it << endl;

d1.insert(d1.end(), 5, 404);
PrintDeque(d1); // 0 1 2 3 4 101 5 6 7 8 9 404 404 404 404 404

d1.insert(d1.begin(), d1.begin(), d1.end());
PrintDeque(d1); // 结果等于源数据+源数据


deque<int>::iterator ite = d1.erase(d1.begin(), d1.end() - 10);
PrintDeque(d1); // 5 6 7 8 9 404 404 404 404 404
cout << "ite = " << *ite << endl; // 5

deque<int>::iterator iter = d1.erase(d1.begin());
PrintDeque(d1); // 6 7 8 9 404 404 404 404 404
cout << "iter = " << *iter << endl; // iter = 6

d1.clear();
d1.empty() ? cout << "d1 is empty" << endl : cout << "d1 is not empty" << endl; // d1 is empty
}

int main() {
cout << "_________ test01 _________" << endl;
test01();
cout << "_________ test02 _________" << endl;
test02();
cout << "_________ test03 _________" << endl;
test03();

return 0;
}

deque数据存取

功能描述:

  • 对deque中的数据存取操作

函数原型:

  • at(int idx); //返回索引idx所指的数据
  • operator[]; //返回索引idx所指的数据
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最后一个数据元素

示例:

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 <string>
#include <deque>
#include <algorithm>

using namespace std;

void test01() {
deque<int> d1;
for (int i = 0; i < 10; i++) {
d1.push_back(i);
}

cout << "deque.at(5):" << d1.at(5) << endl; // deque.at(5):5
cout << "deque[6]:" << d1[6] << endl; // deque[6]:6
cout << "deque.front():" << d1.front() << endl; // deque.front():0
cout << "deque.back():" << d1.back() << endl; // deque.back():9
}

int main() {
test01();

return 0;
}

deque排序

功能描述:

  • 利用算法实现对deque容器进行排序

算法:

  • sort(iterator beg, iterator end); // 对beg和end区间内元素进行排序

示例:

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
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>

using namespace std;

// 打印deque函数
void PrintDeque(deque<int> &d) {
for (deque<int>::iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}

void test01() {
deque<int> d1;
for (int i = 0; i < 10; i++) {
int random_01 = rand() % 10 + 1;
d1.push_back(random_01);
}

PrintDeque(d1); // 假设结果:2 8 5 1 10 5 9 9 3 5

sort(d1.begin(), d1.end());
PrintDeque(d1); // 那么最终结果为:1 2 3 5 5 5 8 9 9 10

sort(d1.begin(), d1.end(), greater<int>()); // 倒序排序
PrintDeque(d1); // 10 9 9 8 5 5 5 3 2 1
}

int main() {
test01();

return 0;
}

stack容器

stack基本概念

概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口

clip_image002-1547604555425

栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为

stack常用接口

功能描述:栈容器常用的对外接口

构造函数:

  • stack<T> stk; //stack采用模板类实现, stack对象的默认构造形式
  • stack(const stack &stk); //拷贝构造函数

赋值操作:

  • stack& operator=(const stack &stk); //重载等号操作符

数据存取:

  • push(elem); //向栈顶添加元素
  • pop(); //从栈顶移除第一个元素
  • top(); //返回栈顶元素

大小操作:

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

示例:

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 <string>
#include <stack>
#include <algorithm>

using namespace std;

void test01() {
stack<int> stk1;

stack<int> stk2(stk1); // 拷贝构造

stack<int> stk3 = stk1; // 重载等号操作符
}

void test02() {
stack<int> stk;
for (int i = 0; i < 10; i++)
{
stk.push(i); // 向栈中压入数据
}

cout << "栈的大小为:" << stk.size() << endl; // 10
cout << "栈顶元素为:" << stk.top() << endl; // 9
stk.pop(); // 弹出栈顶元素
cout << "栈顶元素为:" << stk.top() << endl; // 8
cout << "栈的大小为:" << stk.size() << endl; // 9
cout << "栈是否为空:";
stk.empty() ? cout << "是" << endl : cout << "否" << endl; // 否
}

int main() {
test01();

test02();

return 0;
}

queue容器

queue基本概念

概念:Queue是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口

clip_image002-1547606475892

队列容器允许从一端新增元素,从另一端移除元素

队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为

队列中进数据称为 — 入队 push

队列中出数据称为 — 出队 pop

queue常用接口

功能描述:栈容器常用的对外接口

构造函数:

  • queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
  • queue(const queue &que); //拷贝构造函数

赋值操作:

  • queue& operator=(const queue &que); //重载等号操作符

数据存取:

  • push(elem); //往队尾添加元素
  • pop(); //从队头移除第一个元素
  • back(); //返回最后一个元素
  • front(); //返回第一个元素

大小操作:

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

示例:

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
#include <iostream>
#include <string>
#include <queue>
#include <algorithm>

using namespace std;

void test01() {
queue<int> q1;

queue<int> q2(q1); // 拷贝构造函数
queue<int> q3 = q1; // 重载等号运算符
}

void test02() {
queue<int> q1;

q1.push(10);
q1.push(20);
q1.push(30);

cout << "队列第一个元素:" << q1.front() << endl; // 10
cout << "队列最后一个元素:" << q1.back() << endl; // 30

q1.pop();
cout << "移除队列头部第一个元素后,队列第一个元素:" << q1.front() << endl; // 20

cout << "队列大小:" << q1.size() << endl; // 2
cout << "队列是否为空:";
q1.empty() ? cout << "是" << endl : cout << "否" << endl; // 否
}

int main() {
test01();

test02();

return 0;
}

list容器

list基本概念

功能:将数据进行链式存储

链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

链表的组成:链表由一系列结点组成

结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

STL中的链表是一个双向循环链表(下图有误,实际上第一个元素的prev指向的是链表中的最后一个元素,最后一个元素的next指向的是链表中的第一个元素)

clip_image002-1547608564071

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器

list的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出
  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list的缺点:

  • 链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。

总结:STL中List和vector是两个最常被使用的容器,各有优缺点

list构造函数

功能描述:

  • 创建list容器

函数原型:

  • list<T> lst; //list采用采用模板类实现,对象的默认构造形式:
  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。
  • list(n,elem); //构造函数将n个elem拷贝给本身。
  • list(const list &lst); //拷贝构造函数。

示例:

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
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;
lst01.push_back(10);
lst01.push_back(20);
lst01.push_back(30);

PrintList(lst01); // 10 20 30

// list<int> lst02(lst01.begin() + 1, lst01.end()); // 报错,因为双向迭代器不支持随机访问操作

// 获取迭代器
list<int>::iterator it = lst01.begin();
// 将迭代器移动到第二个元素(值为20)
advance(it, 1);
// 区间在 [20, 30]
list<int> lst02(it, lst01.end());
PrintList(lst02); // 20 30

list<int> lst03(5, 10);
PrintList(lst03); // 10 10 10 10 10

list<int> lst04(lst03);
PrintList(lst04); // 10 10 10 10 10
}


int main() {
test01();

return 0;
}

注意以上代码指出了,list容器由于是双向迭代器,所以不支持随机访问(如iterator + number)

list赋值和交换

功能描述:

  • 给list容器进行赋值,以及交换list容器

函数原型:

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
  • assign(n, elem); //将n个elem拷贝赋值给本身。
  • list& operator=(const list &lst); //重载等号操作符
  • swap(lst); //将lst与本身的元素互换。
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
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;
lst01.push_back(1);
lst01.push_back(2);
lst01.push_back(3);
lst01.push_back(4);
lst01.push_back(5);

list<int> lst02;
list<int>::iterator it = lst01.begin();
advance(it, 3);
lst02.assign(it, lst01.end());
PrintList(lst02); // 4 5

list<int> lst03;
lst03.assign(5, 1);
PrintList(lst03); // 1 1 1 1 1

list<int> lst04 = lst03;
PrintList(lst04);

lst01.swap(lst04);
PrintList(lst01); // 1 1 1 1 1
PrintList(lst04); // 1 2 3 4 5
}


int main() {
test01();

return 0;
}

list大小操作

功能描述:

  • 对list容器的大小进行操作

函数原型:

  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    ​ //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

    ​ //如果容器变短,则末尾超出容器长度的元素被删除。

示例:

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
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;
lst01.push_back(1);
lst01.push_back(2);
lst01.push_back(3);
lst01.push_back(4);
lst01.push_back(5);

cout << "size:" << lst01.size() << endl; // size:5

lst01.empty() ? cout << "链表为空" << endl : cout << "链表不为空" << endl; // 链表不为空

lst01.resize(3); // 1 2 3
PrintList(lst01);

lst01.resize(10, 404);
PrintList(lst01); // 1 2 3 404 404 404 404 404 404 404
}


int main() {
test01();

return 0;
}

list插入和删除

功能描述:

  • 对list容器进行数据的插入和删除

函数原型:

  • push_back(elem);//在容器尾部加入一个元素
  • pop_back();//删除容器中最后一个元素
  • push_front(elem);//在容器开头插入一个元素
  • pop_front();//从容器开头移除第一个元素
  • insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置
  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值
  • clear();//移除容器的所有数据
  • erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置
  • erase(pos);//删除pos位置的数据,返回下一个数据的位置
  • remove(elem);//删除容器中所有与elem值匹配的元素

示例:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;
for (int i = 1; i <= 10; i++)
{
lst01.push_back(i);
}

cout << "源数据: ";
PrintList(lst01);

cout << "After pop_back(): ";
lst01.pop_back();
PrintList(lst01);

cout << "After push_front(5): ";
lst01.push_front(5);
PrintList(lst01);

cout << "After pop_front(): ";
lst01.pop_front();
PrintList(lst01);

cout << "After insert((iterator)3,101): ";
list<int>::iterator it = lst01.begin();
advance(it, 3);
list<int>::iterator ist = lst01.insert(it, 101);
PrintList(lst01);
cout << "insert返回值: " << *ist << endl;

cout << "After insert(lst01.end(),5, 100): ";
lst01.insert(lst01.end(), 5, 100);
PrintList(lst01);

cout << "After insert(pos,beg,end): ";
lst01.insert(lst01.end(), lst01.begin(), lst01.end());
PrintList(lst01);

cout << "After clear(): ";
lst01.clear();
if (!lst01.empty()) { PrintList(lst01); }
else { cout << "lst01 链表为空" << endl; }

for (int i = 1; i <= 5; i++)
{
lst01.push_back(i); // 1 2 3 4 5
}

cout << "After erase(beg, end): ";
it = lst01.end();
advance(it, -2);
list<int>::iterator era = lst01.erase(lst01.begin(), it);
PrintList(lst01);
cout << "erase返回值:" << *era << endl;

cout << "After erase(pos): ";
lst01.clear();
for (int i = 1; i <= 5; i++)
{
lst01.push_back(i);
lst01.push_back(i + 1); // 1 2 2 3 3 4 4 5 5 6
}
lst01.remove(3);
PrintList(lst01);
}


int main() {
test01();

/*
源数据: 1 2 3 4 5 6 7 8 9 10
After pop_back(): 1 2 3 4 5 6 7 8 9
After push_front(5): 5 1 2 3 4 5 6 7 8 9
After pop_front(): 1 2 3 4 5 6 7 8 9
After insert((iterator)3,101): 1 2 3 101 4 5 6 7 8 9
insert返回值: 101
After insert(lst01.end(),5, 100): 1 2 3 101 4 5 6 7 8 9 100 100 100 100 100
After insert(pos,beg,end): 1 2 3 101 4 5 6 7 8 9 100 100 100 100 100 1 2 3 101 4 5 6 7 8 9 100 100 100 100 100
After clear(): lst01 链表为空
After erase(beg, end): 4 5
erase返回值: 4
After erase(pos): 1 2 2 4 4 5 5 6

*/

return 0;
}

list数据存取

功能描述:

  • 对list容器中数据进行存取

函数原型:

  • front(); //返回第一个元素
  • back(); //返回最后一个元素

示例:

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
#include <iostream>
#include <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;
for (int i = 1; i <= 5; i++)
{
lst01.push_back(i);
}

cout << "lst01:";
PrintList(lst01);

cout << "lst01.front(): " << lst01.front() << endl;
cout << "lst01.back(): " << lst01.back() << endl;
}


int main() {
test01();

return 0;
}

list反转和排序

功能描述:

  • 将容器中的元素反转,以及将容器中的数据进行排序

函数原型:

  • reverse(); //反转链表
  • sort(); //链表排序

示例:

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 <string>
#include <list>
#include <algorithm>

using namespace std;

// 打印list函数模板
template<typename T>
void PrintList(const list<T>& t) {
for (typename list<T>::const_iterator cit = t.begin(); cit != t.end();cit++)
{
cout << *cit << " ";
}
cout << endl;
}

void test01() {
list<int> lst01;

for (int i = 1; i <= 10 ; i++)
{
int random_01 = rand() % 100;
lst01.push_back(random_01);
}
PrintList(lst01); // 41 67 34 0 69 24 78 58 62 64

lst01.sort();
PrintList(lst01); // 0 24 34 41 58 62 64 67 69 78

lst01.reverse();
PrintList(lst01); // 78 69 67 64 62 58 41 34 24 0
}


int main() {
test01();

return 0;
}

set / multiset容器

简介:

  • 所有元素都会在插入时自动被排序

本质:

  • set / multiset属于关联式容器,底层架构是二叉树实现

set和multiset区别:

  • set不允许容器中有重复的元素
  • multiset允许容器中有重复的元素

注意:

  • 默认情况下,不能存放自定义数据,这是因为编译器并不知道该如何排序
  • 如果想要存放自定义数据,那么就需要通过伪函数指定排序规则

set构造和赋值

功能描述:创建set容器以及赋值

构造:

  • set<T> st; //默认构造函数:
  • set(const set &st); //拷贝构造函数

赋值:

  • set& operator=(const set &st); //重载等号操作符

示例:

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 <string>
#include <set>
#include <algorithm>

using namespace std;

template <typename T>
void PrintSet(const set<T>& st) {
for (typename set<T>::const_iterator it = st.begin(); it != st.end() ; it++)
{
cout << *it << " ";
}
cout << endl;
}

int main() {
set<int> st1;

set<int> st2(st1);

set<int> st3 = st2;

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

PrintSet(st1); // 10 20 30

st2.insert(3);
st2.insert(2);
st2.insert(5);
st2.insert(1);
st2.insert(4);
PrintSet(st2); // 1 2 3 4 5

st2.insert(5); // 插入重复的数会被过滤
PrintSet(st2); // 1 2 3 4 5

return 0;
}

set插入数据需要使用insert(elem)

set插入的数据会自动排序

set大小和交换

功能描述:

  • 统计set容器大小以及交换set容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器

示例:

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
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

template <typename T>
void PrintSet(const set<T>& st) {
for (typename set<T>::const_iterator it = st.begin(); it != st.end() ; it++)
{
cout << *it << " ";
}
cout << endl;
}

void test01() {
set<int> st1;
cout << "size:" << st1.size() << endl;
st1.empty() ? cout << "set为空" << endl : cout << "set不为空" << endl;

set<int> st2;
for (int i = 0; i < 10; i++)
{
st1.insert(i + 1);
st2.insert(i + 11);
}

cout << "st1 和 st2 交换前:" << endl;
cout << "st1: ";
PrintSet(st1); // 1 2 3 4 5 6 7 8 9 10
cout << "st2: ";
PrintSet(st2); // 11 12 13 14 15 16 17 18 19 20


cout << "st1 和 st2 交换后:" << endl;
st1.swap(st2);
cout << "st1: ";
PrintSet(st1); // 11 12 13 14 15 16 17 18 19 20
cout << "st2: ";
PrintSet(st2); // 1 2 3 4 5 6 7 8 9 10
}

int main() {
test01();

return 0;
}

set插入和删除

功能描述:

  • set容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(elem); //删除容器中值为elem的元素。

示例:

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 <string>
#include <set>
#include <algorithm>

using namespace std;

template <typename T>
void PrintSet(const set<T>& st) {
for (typename set<T>::const_iterator it = st.begin(); it != st.end() ; it++)
{
cout << *it << " ";
}
cout << endl;
}

void test01() {
set<int> st1;

st1.insert(1);
st1.insert(2);
st1.insert(3);

st1.clear();
cout << "size:" << st1.size() << endl;

for (int i = 0; i < 20; i++)
{
int random = rand() % 20;
st1.insert(random);
}

cout << "\n__________第一次擦除erase(pos)__________" << endl;
PrintSet(st1); // 0 1 2 4 5 7 9 11 14 15 16 18
set<int>::iterator beg = st1.begin();
advance(beg, 4);
set<int>::iterator era01 = st1.erase(beg);
cout << "删除后下个元素是: " << *era01 << endl;
PrintSet(st1); // 0 1 2 4 7 9 11 14 15 16 18


cout << "\n__________第二次擦除erase(beg,end)__________" << endl;
beg = st1.begin();
advance(beg, 3);
set<int>::iterator end = st1.end();
// 安全获取倒数第三个元素的位置
set<int>::iterator del_end = prev(end, 3);
set<int>::iterator era02 = st1.erase(beg, del_end);
cout << "删除后下个元素是: " << *era02 << endl; // 15
PrintSet(st1); // 0 1 2 15 16 18

cout << "\n__________第三次擦除erase(elem)__________" << endl;
st1.erase(0);
PrintSet(st1); // 1 2 15 16 18
}

int main() {
test01();

return 0;
}

set查找和统计

功能描述:

  • 对set容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计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
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

template <typename T>
void PrintSet(const set<T>& st) {
for (typename set<T>::const_iterator it = st.begin(); it != st.end() ; it++)
{
cout << *it << " ";
}
cout << endl;
}

void test01() {
// find
set<int> st1;
for (int i = 1; i <= 5; i++)
{
st1.insert(i * 10);
}

set<int>::iterator it1 = st1.find(30);
cout << *it1 << endl; // 30

st1.erase(it1);
PrintSet(st1); // 10 20 40 50

set<int>::iterator it2 = st1.find(100);
set<int>::iterator end = st1.end();

it2 == end ? cout << "等于" << endl : cout << "不等于" << endl; // 等于
}

void test02() {
// count
set<int> st1;
for (int i = 1; i <= 5; i++)
{
st1.insert(i * 10);
}

cout << "set中有 " << st1.count(10) << "个10" << endl; // set中有 1个10
cout << "set中有 " << st1.count(60) << "个60" << endl; // set中有 0个60
}

int main() {
test01();
test02();
return 0;
}

实质上,普通的set容器并不需要count方法,而将设计到set容器中是为了与 multisetmap 等共享方法,同一套逻辑可以兼容 setmultiset

set和multiset区别

区别:

  • set不可以插入重复数据,而multiset可以
  • set插入数据的同时会返回插入结果,表示插入是否成功
  • multiset不会检测数据,因此可以插入重复数据

示例:

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
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

template <typename T>
void PrintSet(const set<T>& st) {
for (typename set<T>::const_iterator it = st.begin(); it != st.end() ; it++)
{
cout << *it << " ";
}
cout << endl;
}

template <typename T>
void PrintSet(const multiset<T>& st) {
for (typename multiset<T>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}

void test01() {
set<int> st1;
pair<set<int>::iterator,bool> result_01 = st1.insert(10);
if (result_01.second) {
cout << "插入数据成功" << endl; // 第一次插入执行成功
}
else {
cout << "插入数据失败" << endl;
}

pair<set<int>::iterator, bool> result_02 = st1.insert(10);
if (result_02.second) {
cout << "插入数据成功" << endl;
}
else {
cout << "插入数据失败" << endl; // 第二次执行插入失败
}
}

void test02() {
multiset<int> mst;
mst.insert(10);
mst.insert(10);
mst.insert(11);
mst.insert(11);
PrintSet(mst); // 10 10 11 11
}

int main() {
test01();
test02();
return 0;
}

pair对组创建

功能描述:

  • 成对出现的数据,利用对组可以返回两个数据

两个创建方式:

  • pair<type, type> p (value, value);
  • pair<type, type> p = make_pair(value1, value2);

示例:

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
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

class Person {
public:
string name;
int age;

Person(string name, int age) {
this->age = age;
this->name = name;
}

Person() : name("无名"), age(-1) {};
};

void test01() {
pair<int, string> p1(10, "hello");
cout << "p1的第一个数据:" << p1.first << endl; // 10
cout << "p1的第二个数据:" << p1.second << endl; // hello

Person zs("张三", 18);
pair<Person, bool> p2 = make_pair(zs, false);

cout << "p1的第一个数据:" << p2.first.name << p2.first.age << endl; // 张三18
cout << "p1的第二个数据:" << p2.second << endl; // 0
}



int main() {
test01();

return 0;
}

set排序

主要技术点:

set容器默认情况下的排序规则为从小到大,利用仿函数,可以改变排序规则

示例一

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

class MyCompare {
public:
bool operator()(int v1, int v2) const { // 仿函数一定要限制为const才行(C++11后的规定)
return v1 > v2;
}
};

template<typename T>
void PrintSet(const set<T>& st) {

for (typename set<T>::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}

template<typename T1,typename T2>
void PrintSet(set<T1,T2>& st) {

for (typename set<T1,T2>::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}

void test01() {
set<int> st1;
st1.insert(10);
st1.insert(30);
st1.insert(50);
st1.insert(20);
st1.insert(40);
PrintSet(st1); // 10 20 30 40 50

// 利用仿函数修改排序规则
set<int, MyCompare> st2;
st2.insert(10);
st2.insert(30);
st2.insert(50);
st2.insert(20);
st2.insert(40);
PrintSet(st2); // 50 40 30 20 10
}



int main() {
test01();

return 0;
}

示例二

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <string>
#include <set>
#include <algorithm>

using namespace std;

class Person {
public:
string name;
int age;

Person() : name("无名"), age(-1) {};

Person(string name, int age) {
this->name = name;
this->age = age;
}
};

class MyCompare {
public:
bool operator()(const Person& v1,const Person& v2) const {
return v1.age > v2.age; // 年龄倒序排序
}
};

void test01() {
Person p1("张三", 19);
Person p2("李四", 20);
Person p3("王五", 18);
Person p4("赵六", 21);

set<Person, MyCompare> st1;
st1.insert(p1);
st1.insert(p2);
st1.insert(p3);
st1.insert(p4);

for (set<Person,MyCompare>::iterator it = st1.begin(); it != st1.end(); it++)
{
cout << "姓名:" << it->name << ",年龄:" << it->age << endl;
}

/*
姓名:赵六,年龄:21
姓名:李四,年龄:20
姓名:张三,年龄:19
姓名:王五,年龄:18
*/
}



int main() {
test01();

return 0;
}

map / multimap容器

map基本概念

简介:

  • map中所有元素都是pair
  • pair中第一个元素为key(键值),起到索引作用,第二个为value(实值)
  • 所有元素都会根据元素的键值自动排序

本质:

  • map/multimap属于关联式容器,底层结构是二叉树实现

优点:

  • 可以根据key值快速找到value值

map和multimap区别:

  • map不允许容器中有重复key值元素
  • multimap允许容器中有重复key值元素

map的特性:

mapoperator[] 是独立于迭代器的机制,其核心依赖红黑树的查找逻辑,也就说可以通过map[key]来访问数据

map构造和赋值

功能描述:

  • 对map容器进行构造和赋值操作

函数原型:

构造:

  • map<T1, T2> mp; //map默认构造函数:
  • map(const map &mp); //拷贝构造函数

赋值:

  • map& operator=(const map &mp); //重载等号操作符

示例:

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
#include <iostream>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

void test01() {
map<int, int> m1;

map<int, int> m2(m1);

map<int, int> m3 = m2;

m3.insert(pair<int, int>(1, 11));
m3.insert(pair<int, int>(4, 44));
m3.insert(pair<int, int>(4, 44));
m3.insert(pair<int, int>(2, 22));
m3.insert(pair<int, int>(5, 55));
m3.insert(pair<int, int>(3, 33));
m3.insert(pair<int, int>(3, 33));

for (map<int,int>::iterator it = m3.begin(); it != m3.end(); it++)
{
cout << "Key" << it->first << ",Value:" << it->second << endl;
}
}



int main() {
test01();

/*
自动排序,不存在重复key
Key1,Value:11
Key2,Value:22
Key3,Value:33
Key4,Value:44
Key5,Value:55
*/

return 0;
}

map大小和交换

功能描述:

  • 统计map容器大小以及交换map容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器

示例:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

template<typename T1,typename T2>
void PrintMap(map<T1, T2>& mp) {
for (typename map<T1,T2>::iterator it = mp.begin(); it != mp.end(); it++)
{
cout << "Key:" << it->first << ",Value:" << it->second << endl;
}
}

void test01() {
map<int, int> m1;
map<int, int> m2;

m1.empty() ? cout << "map容器为空" << endl : cout << "map容器不为空" << endl; // map容器为空

for (int i = 0; i < 5; i++)
{
m1.insert({ i, rand() % 10 });
m2.insert({ i + 10, rand() % 10 });
}

cout << "map容器大小为:" << m1.size() << endl; // map容器大小为:5

cout << "Map1:" << endl;
PrintMap(m1);
cout << endl;
cout << "Map2:" << endl;
PrintMap(m2);
/*
Map1:
Key:0,Value:1
Key:1,Value:4
Key:2,Value:9
Key:3,Value:8
Key:4,Value:2

Map2:
Key:10,Value:7
Key:11,Value:0
Key:12,Value:4
Key:13,Value:8
Key:14,Value:4
*/

cout << "After Swap:" << endl;
m1.swap(m2);
cout << "Map1:" << endl;
PrintMap(m1);
cout << endl;
cout << "Map2:" << endl;
PrintMap(m2);
/*
Map1:
Key:10,Value:7
Key:11,Value:0
Key:12,Value:4
Key:13,Value:8
Key:14,Value:4

Map2:
Key:0,Value:1
Key:1,Value:4
Key:2,Value:9
Key:3,Value:8
Key:4,Value:2
*/
}



int main() {
test01();

return 0;
}

map插入和删除

功能描述:

  • map容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(key); //删除容器中值为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
#include <iostream>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

template<typename T1,typename T2>
void PrintMap(map<T1, T2>& mp) {
for (typename map<T1,T2>::iterator it = mp.begin(); it != mp.end(); it++)
{
cout << "Key:" << it->first << ",Value:" << it->second << endl;
}
}

void test01() {
map<int, int> m1;

m1.insert(pair<int, int>(1, 100));
m1.insert({ 2, 101 });
m1.insert(make_pair(3, 102));
m1.insert(map<int,int>::value_type(4, 103));
m1[5] = 104;

cout << "原始数据:" << endl;
PrintMap(m1);
cout << "第一次擦除:" << endl;
m1.erase(m1.begin());
PrintMap(m1);

cout << "第二次擦除:" << endl;
map<int, int>::iterator beg = m1.begin();
advance(beg, 2);
map<int, int>::iterator end = prev(m1.end(), 1);
m1.erase(beg, end);

PrintMap(m1);

cout << "第三次擦除:" << endl;
m1.erase(2);
PrintMap(m1);

m1.clear();
cout << m1.empty() << endl;
}



int main() {
test01();

return 0;
}

map查找和统计

功能描述:

  • 对map容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计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
#include <map>

//查找和统计
void test01()
{
map<int, int>m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));

//查找
map<int, int>::iterator pos = m.find(3);

if (pos != m.end())
{
cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
}
else
{
cout << "未找到元素" << endl;
}

//统计
int num = m.count(3);
cout << "num = " << num << endl;
}

int main() {

test01();

system("pause");

return 0;
}

map容器排序

同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
#include <map>

class MyCompare {
public:
bool operator()(int v1, int v2) {
return v1 > v2;
}
};

void test01()
{
//默认从小到大排序
//利用仿函数实现从大到小排序
map<int, int, MyCompare> m;

m.insert(make_pair(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(3, 30));
m.insert(make_pair(4, 40));
m.insert(make_pair(5, 50));

for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
cout << "key:" << it->first << " value:" << it->second << endl;
}
}
int main() {

test01();

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
52
53
54
55
56
#include <iostream>
#include <string>
#include <map>
#include <algorithm>

using namespace std;

class MyADD {
public:
int operator()(int a, int b) {
return a + b;
}
};

class MyPrint {
public:
int count = 0;

void operator()(string s) {
cout << s << endl;
count++;
}
};

// 将仿函数作为参数
void doPrint(MyPrint& mp, string s) {
mp(s);
}

void test01() {
// 基本使用
MyADD myAdd;

cout << myAdd(10, 20) << endl;

// 记录状态
MyPrint myPrint;
myPrint("Hello World");
myPrint("Hello World");
myPrint("Hello World");
myPrint("Hello World");

cout << "打印次数为:" << myPrint.count << endl; // 4


// 仿函数做参数调用
doPrint(myPrint, "Hello C++");
}



int main() {
test01();

return 0;
}

谓词

谓词概念

概念:

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数,那么叫做一元谓词
  • 如果operator()接受两个参数,那么叫做二元谓词

一元谓词

示例:

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 <string>
#include <vector>
#include <algorithm>

using namespace std;

class BiggerThanFive {
public:
// 一元谓词
bool operator()(int a) {
return a > 5;
}
};

void test01() {
vector<int> v1;
for (int i = 1; i <= 10; i++)
{
v1.push_back(i);
}

vector<int>::iterator it = find_if(v1.begin(), v1.end(), BiggerThanFive());
if (it != v1.end()) {
cout << "比5大的数字为:" << *it << endl; // 比5大的数字为:6
}
else {
cout << "未找到比5大的数字" << endl;
}
}



int main() {
test01();

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class MyCompare {
public:
// 一元谓词
bool operator()(int a,int b) {
return a > b;
}
};

void test01() {
vector<int> v1;
v1.push_back(3);
v1.push_back(2);
v1.push_back(1);
v1.push_back(5);
v1.push_back(4);

sort(v1.begin(), v1.end());
for (auto it = v1.begin(); it != v1.end(); it++)
{
cout << *it << " "; // 1 2 3 4 5
}
cout << endl;

cout << "------降序排序------" << endl;
sort(v1.begin(), v1.end(), MyCompare());
for (auto it = v1.begin(); it != v1.end(); it++)
{
cout << *it << " "; // 5 4 3 2 1
}
cout << endl;
}



int main() {
test01();

return 0;
}

内建函数对象

内建函数对象意义

概念:

  • STL内建了一些函数对象

分类:

  • 算数仿函数
  • 关系仿函数
  • 逻辑仿函数

用法:

  • 这些仿函数所产生的对象,用法和一般函数完全相同
  • 使用内建函数对象,需要引入头文件#include <functional>

算数仿函数

功能描述:

  • 实现四则运算
  • 其中negate是一元运算,其他都是二元运算

仿函数原型:

  • template<class T> T plus<T> //加法仿函数
  • template<class T> T minus<T> //减法仿函数
  • template<class T> T multiplies<T> //乘法仿函数
  • template<class T> T divides<T> //除法仿函数
  • template<class T> T modulus<T> //取模仿函数
  • template<class T> T negate<T> //取反仿函数

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;



void test01() {
// negate 一元仿函数 取反仿函数
negate<int>a;
cout << "10取反为: " << a(10) << endl; // 10取反为: -10
}

void test02() {
// plus 二元仿函数 加法仿函数
plus<int>a;
cout << "10 + 11 = " << a(10, 11) << endl; // 10 + 11 = 21
}



int main() {
test01();

test02();

return 0;
}

关系仿函数

功能描述:

  • 实现关系对比

仿函数原型:

  • template<class T> bool equal_to<T> //等于
  • template<class T> bool not_equal_to<T> //不等于
  • template<class T> bool greater<T> //大于
  • template<class T> bool greater_equal<T> //大于等于
  • template<class T> bool less<T> //小于
  • template<class T> bool less_equal<T> //小于等于

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;



void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(rand() % 100);
}

sort(v1.begin(), v1.end(), greater<>()); // 可以直接利用greate<>()仿函数实现倒序

for (auto it = v1.begin(); it != v1.end() ; it++)
{
cout << *it << " "; // 78 69 67 64 62 58 41 34 24 0
}
cout << endl;
}




int main() {
test01();


return 0;
}

自定义数据排序需要重载>操作符<操作符

逻辑仿函数

功能描述:

  • 实现逻辑运算

函数原型:

  • template<class T> bool logical_and<T> //逻辑与
  • template<class T> bool logical_or<T> //逻辑或
  • template<class T> bool logical_not<T> //逻辑非

示例:

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 <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;



void test01() {
vector<bool> v1;
v1.push_back(false);
v1.push_back(true);
v1.push_back(false);
v1.push_back(true);

// v1:0 1 0 1
logical_not<bool> ln;
vector<bool> v2;
for (auto it = v1.begin(); it != v1.end(); it++)
{
v2.push_back(ln(*it)); // 将v1容器取反赋值给v2
}

for (auto it = v2.begin(); it != v2.end(); it++)
{
cout << *it << " "; // v2:1 0 1 0
}
cout << endl;
}




int main() {
test01();


return 0;
}

常用算法

概述:

  • 算法主要是由头文件<algorithm>functinalnumeric组成
  • <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等`
  • <numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数
  • <functional>定义了一些模板类,用以声明函数对象

常用遍历算法

算法简介:

  • for_each // 遍历容器

  • transform // 搬运容器到另一个容器中

for_each

功能描述:

  • 实现遍历容器

函数原型:

  • for_each(iterator beg,iterator end, _func);
    • beg:开始迭代器
    • end:结束迭代器
    • _func:普通函数或者函数对象

示例:

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
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

// 普通函数
void Print01(int val) { cout << val << " "; }

// 仿函数
class Print02 {
public:
void operator() (int val) {
cout << val << " ";
}
};

void test01() {
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(rand() % 100);
}

for_each(v1.begin(), v1.end(), Print01); // 普通函数打印遍历数据
cout << endl;
for_each(v1.begin(), v1.end(), Print02()); // 仿函数打印遍历数据
}

int main() {
test01();


return 0;
}

注意普通函数和仿函数作为参数的区别

transform

功能描述:

  • 搬运容器到另一个容器中

函数原型:

  • transform(iterator beg1,iterator end1, iterator beg2, _func);
    • beg1:源容器开始迭代器
    • end1:源容器结束迭代器
    • beg2:目标容器开始迭代器
    • _func:普通函数或者仿函数

示例:

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 <string>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;


void test01() {
vector<int> v1;
for (int i = 0; i < 5; i++)
{
v1.push_back(i); // v1 : 0 1 2 3 4
}

vector<int> v2;
v2.resize(v1.size());

transform(v1.begin(), v1.end(), v2.begin(), [](int x) { return x + 10; }); // lambda表达式

for (auto it = v2.begin(); it != v2.end(); it++)
{
cout << *it << " "; // v2 : 10 11 12 13 14
}
cout << endl;
}


int main() {
test01();

return 0;
}

常用查找算法

算法简介:

  • find //查找元素
  • find_if //按条件查找元素
  • adjacent_find //查找相邻重复元素
  • binary_search //二分查找法
  • count //统计元素个数
  • count_if //按条件统计元素个数

find

功能描述:

  • 查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()

函数原型:

  • find(iterator beg, iterator end, value);

    // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

    // beg 开始迭代器

    // end 结束迭代器

    // value 查找的元素

示例:

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
65
66
67
68
#include <algorithm>
#include <vector>
#include <string>
void test01() {

vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i + 1);
}
//查找容器中是否有 5 这个元素
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it == v.end())
{
cout << "没有找到!" << endl;
}
else
{
cout << "找到:" << *it << endl;
}
}

class Person {
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
//重载==
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
return false;
}

public:
string m_Name;
int m_Age;
};

void test02() {

vector<Person> v;

//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);

v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);

vector<Person>::iterator it = find(v.begin(), v.end(), p2);
if (it == v.end())
{
cout << "没有找到!" << endl;
}
else
{
cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;
}
}

总结: 利用find可以在容器中找指定的元素,返回值是迭代器

find_if

功能描述:

  • 按条件查找元素

函数原型:

  • find_if(iterator beg, iterator end, _Pred);

    // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

    // beg 开始迭代器

    // end 结束迭代器

    // _Pred 函数或者谓词(返回bool类型的仿函数)

示例:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <algorithm>
#include <vector>
#include <string>

//内置数据类型
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};

void test01() {

vector<int> v;
for (int i = 0; i < 10; i++) {
v.push_back(i + 1);
}

vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end()) {
cout << "没有找到!" << endl;
}
else {
cout << "找到大于5的数字:" << *it << endl;
}
}

//自定义数据类型
class Person {
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
public:
string m_Name;
int m_Age;
};

class Greater20
{
public:
bool operator()(Person &p)
{
return p.m_Age > 20;
}

};

void test02() {

vector<Person> v;

//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);

v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);

vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());
if (it == v.end())
{
cout << "没有找到!" << endl;
}
else
{
cout << "找到姓名:" << it->m_Name << " 年龄: " << it->m_Age << endl;
}
}

int main() {

//test01();

test02();

system("pause");

return 0;
}

总结:find_if按条件查找使查找更加灵活,提供的仿函数可以改变不同的策略

adjacent_find

功能描述:

  • 查找相邻重复元素

函数原型:

  • adjacent_find(iterator beg, iterator end);

    // 查找相邻重复元素,返回相邻元素的第一个位置的迭代器

    // beg 开始迭代器

    // end 结束迭代器

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <algorithm>
#include <vector>

void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(5);
v.push_back(2);
v.push_back(4);
v.push_back(4);
v.push_back(3);

//查找相邻重复元素
vector<int>::iterator it = adjacent_find(v.begin(), v.end());
if (it == v.end()) {
cout << "找不到!" << endl;
}
else {
cout << "找到相邻重复元素为:" << *it << endl;
}
}

总结:面试题中如果出现查找相邻重复元素,记得用STL中的adjacent_find算法

功能描述:

  • 查找指定元素是否存在

函数原型:

  • bool binary_search(iterator beg, iterator end, value);

    // 查找指定的元素,查到 返回true 否则false

    // 注意: 在无序序列中不可用

    // beg 开始迭代器

    // end 结束迭代器

    // value 查找的元素

示例:

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
#include <algorithm>
#include <vector>

void test01()
{
vector<int>v;

for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//二分查找
bool ret = binary_search(v.begin(), v.end(),2);
if (ret)
{
cout << "找到了" << endl;
}
else
{
cout << "未找到" << endl;
}
}

int main() {

test01();

system("pause");

return 0;
}

总结:二分查找法查找效率很高,值得注意的是查找的容器中元素必须的有序序列

count

功能描述:

  • 统计元素个数

函数原型:

  • count(iterator beg, iterator end, value);

    // 统计元素出现次数

    // beg 开始迭代器

    // end 结束迭代器

    // value 统计的元素

示例:

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
65
66
67
68
69
70
71
72
73
74
75
#include <algorithm>
#include <vector>

//内置数据类型
void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.push_back(4);
v.push_back(4);

int num = count(v.begin(), v.end(), 4);

cout << "4的个数为: " << num << endl;
}

//自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
bool operator==(const Person & p)
{
if (this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};

void test02()
{
vector<Person> v;

Person p1("刘备", 35);
Person p2("关羽", 35);
Person p3("张飞", 35);
Person p4("赵云", 30);
Person p5("曹操", 25);

v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);

Person p("诸葛亮",35);

int num = count(v.begin(), v.end(), p);
cout << "num = " << num << endl;
}
int main() {

//test01();

test02();

system("pause");

return 0;
}

总结: 统计自定义数据类型时候,需要配合重载 operator==

count_if

功能描述:

  • 按条件统计元素个数

函数原型:

  • count_if(iterator beg, iterator end, _Pred);

    // 按条件统计元素出现次数

    // beg 开始迭代器

    // end 结束迭代器

    // _Pred 谓词

示例:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <algorithm>
#include <vector>

class Greater4
{
public:
bool operator()(int val)
{
return val >= 4;
}
};

//内置数据类型
void test01()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(5);
v.push_back(3);
v.push_back(4);
v.push_back(4);

int num = count_if(v.begin(), v.end(), Greater4());

cout << "大于4的个数为: " << num << endl;
}

//自定义数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}

string m_Name;
int m_Age;
};

class AgeLess35
{
public:
bool operator()(const Person &p)
{
return p.m_Age < 35;
}
};
void test02()
{
vector<Person> v;

Person p1("刘备", 35);
Person p2("关羽", 35);
Person p3("张飞", 35);
Person p4("赵云", 30);
Person p5("曹操", 25);

v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);

int num = count_if(v.begin(), v.end(), AgeLess35());
cout << "小于35岁的个数:" << num << endl;
}


int main() {

//test01();

test02();

system("pause");

return 0;
}

总结:按值统计用count,按条件统计用count_if

常用排序算法

学习目标:

  • 掌握常用的排序算法

算法简介:

  • sort //对容器内元素进行排序
  • random_shuffle //洗牌 指定范围内的元素随机调整次序
  • merge // 容器元素合并,并存储到另一容器中
  • reverse // 反转指定范围的元素

sort

功能描述:

  • 对容器内元素进行排序

函数原型:

  • sort(iterator beg, iterator end, _Pred);

    // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

    // beg 开始迭代器

    // end 结束迭代器

    // _Pred 谓词

示例:

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
#include <algorithm>
#include <vector>

void myPrint(int val)
{
cout << val << " ";
}

void test01() {
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);

//sort默认从小到大排序
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
cout << endl;

//从大到小排序
sort(v.begin(), v.end(), greater<int>());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:sort属于开发中最常用的算法之一,需熟练掌握

random_shuffle

功能描述:

  • 洗牌 指定范围内的元素随机调整次序

函数原型:

  • random_shuffle(iterator beg, iterator end);

    // 指定范围内的元素随机调整次序

    // beg 开始迭代器

    // end 结束迭代器

示例:

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 <algorithm>
#include <vector>
#include <ctime>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
srand((unsigned int)time(NULL));
vector<int> v;
for(int i = 0 ; i < 10;i++)
{
v.push_back(i);
}
for_each(v.begin(), v.end(), myPrint());
cout << endl;

//打乱顺序
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:random_shuffle洗牌算法比较实用,使用时记得加随机数种子

merge

功能描述:

  • 两个容器元素合并,并存储到另一容器中

函数原型:

  • merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 容器元素合并,并存储到另一容器中

    // 注意: 两个容器必须是有序的

    // beg1 容器1开始迭代器
    // end1 容器1结束迭代器
    // beg2 容器2开始迭代器
    // end2 容器2结束迭代器
    // dest 目标容器开始迭代器

示例:

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
#include <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10 ; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}

vector<int> vtarget;
//目标容器需要提前开辟空间
vtarget.resize(v1.size() + v2.size());
//合并 需要两个有序序列
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());
for_each(vtarget.begin(), vtarget.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:merge合并的两个容器必须的有序序列

reverse

功能描述:

  • 将容器内元素进行反转

函数原型:

  • reverse(iterator beg, iterator end);

    // 反转指定范围的元素

    // beg 开始迭代器

    // end 结束迭代器

示例:

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 <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);

cout << "反转前: " << endl;
for_each(v.begin(), v.end(), myPrint());
cout << endl;

cout << "反转后: " << endl;

reverse(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:reverse反转区间内元素,面试题可能涉及到

常用拷贝和替换算法

学习目标:

  • 掌握常用的拷贝和替换算法

算法简介:

  • copy // 容器内指定范围的元素拷贝到另一容器中
  • replace // 将容器内指定范围的旧元素修改为新元素
  • replace_if // 容器内指定范围满足条件的元素替换为新元素
  • swap // 互换两个容器的元素

copy

功能描述:

  • 容器内指定范围的元素拷贝到另一容器中

函数原型:

  • copy(iterator beg, iterator end, iterator dest);

    // 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置

    // beg 开始迭代器

    // end 结束迭代器

    // dest 目标起始迭代器

示例:

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 <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++) {
v1.push_back(i + 1);
}
vector<int> v2;
v2.resize(v1.size());
copy(v1.begin(), v1.end(), v2.begin());

for_each(v2.begin(), v2.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:利用copy算法在拷贝时,目标容器记得提前开辟空间

replace

功能描述:

  • 将容器内指定范围的旧元素修改为新元素

函数原型:

  • replace(iterator beg, iterator end, oldvalue, newvalue);

    // 将区间内旧元素 替换成 新元素

    // beg 开始迭代器

    // end 结束迭代器

    // oldvalue 旧元素

    // newvalue 新元素

示例:

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
#include <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v;
v.push_back(20);
v.push_back(30);
v.push_back(20);
v.push_back(40);
v.push_back(50);
v.push_back(10);
v.push_back(20);

cout << "替换前:" << endl;
for_each(v.begin(), v.end(), myPrint());
cout << endl;

//将容器中的20 替换成 2000
cout << "替换后:" << endl;
replace(v.begin(), v.end(), 20,2000);
for_each(v.begin(), v.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:replace会替换区间内满足条件的元素

replace_if

功能描述:

  • 将区间内满足条件的元素,替换成指定元素

函数原型:

  • replace_if(iterator beg, iterator end, _pred, newvalue);

    // 按条件替换元素,满足条件的替换成指定元素

    // beg 开始迭代器

    // end 结束迭代器

    // _pred 谓词

    // newvalue 替换的新元素

示例:

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
#include <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

class ReplaceGreater30
{
public:
bool operator()(int val)
{
return val >= 30;
}

};

void test01()
{
vector<int> v;
v.push_back(20);
v.push_back(30);
v.push_back(20);
v.push_back(40);
v.push_back(50);
v.push_back(10);
v.push_back(20);

cout << "替换前:" << endl;
for_each(v.begin(), v.end(), myPrint());
cout << endl;

//将容器中大于等于的30 替换成 3000
cout << "替换后:" << endl;
replace_if(v.begin(), v.end(), ReplaceGreater30(), 3000);
for_each(v.begin(), v.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:replace_if按条件查找,可以利用仿函数灵活筛选满足的条件

swap

功能描述:

  • 互换两个容器的元素

函数原型:

  • swap(container c1, container c2);

    // 互换两个容器的元素

    // c1容器1

    // c2容器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
41
42
43
#include <algorithm>
#include <vector>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
v2.push_back(i+100);
}

cout << "交换前: " << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
for_each(v2.begin(), v2.end(), myPrint());
cout << endl;

cout << "交换后: " << endl;
swap(v1, v2);
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
for_each(v2.begin(), v2.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:swap交换容器时,注意交换的容器要同种类型

常用算术生成算法

学习目标:

  • 掌握常用的算术生成算法

注意:

  • 算术生成算法属于小型算法,使用时包含的头文件为 #include <numeric>

算法简介:

  • accumulate // 计算容器元素累计总和

  • fill // 向容器中添加元素

accumulate

功能描述:

  • 计算区间内 容器元素累计总和

函数原型:

  • accumulate(iterator beg, iterator end, value);

    // 计算容器元素累计总和

    // beg 开始迭代器

    // end 结束迭代器

    // value 起始值

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <numeric>
#include <vector>
void test01()
{
vector<int> v;
for (int i = 0; i <= 100; i++) {
v.push_back(i);
}

int total = accumulate(v.begin(), v.end(), 0);

cout << "total = " << total << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:accumulate使用时头文件注意是 numeric,这个算法很实用

fill

功能描述:

  • 向容器中填充指定的元素

函数原型:

  • fill(iterator beg, iterator end, value);

    // 向容器中填充元素

    // beg 开始迭代器

    // end 结束迭代器

    // value 填充的值

示例:

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
#include <numeric>
#include <vector>
#include <algorithm>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{

vector<int> v;
v.resize(10);
//填充
fill(v.begin(), v.end(), 100);

for_each(v.begin(), v.end(), myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:利用fill可以将容器区间内元素填充为 指定的值

常用集合算法

学习目标:

  • 掌握常用的集合算法

算法简介:

  • set_intersection // 求两个容器的交集

  • set_union // 求两个容器的并集

  • set_difference // 求两个容器的差集

set_intersection

功能描述:

  • 求两个容器的交集

函数原型:

  • set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的交集

    // 注意:两个集合必须是有序序列

    // beg1 容器1开始迭代器
    // end1 容器1结束迭代器
    // beg2 容器2开始迭代器
    // end2 容器2结束迭代器
    // dest 目标容器开始迭代器

示例:

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
#include <vector>
#include <algorithm>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i+5);
}

vector<int> vTarget;
//取两个里面较小的值给目标容器开辟空间
vTarget.resize(min(v1.size(), v2.size()));

//返回目标容器的最后一个元素的迭代器地址
vector<int>::iterator itEnd =
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:

  • 求交集的两个集合必须的有序序列
  • 目标容器开辟空间需要从两个容器中取小值
  • set_intersection返回值既是交集中最后一个元素的位置

set_union

功能描述:

  • 求两个集合的并集

函数原型:

  • set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的并集

    // 注意:两个集合必须是有序序列

    // beg1 容器1开始迭代器
    // end1 容器1结束迭代器
    // beg2 容器2开始迭代器
    // end2 容器2结束迭代器
    // dest 目标容器开始迭代器

示例:

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 <vector>
#include <algorithm>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
v2.push_back(i+5);
}

vector<int> vTarget;
//取两个容器的和给目标容器开辟空间
vTarget.resize(v1.size() + v2.size());

//返回目标容器的最后一个元素的迭代器地址
vector<int>::iterator itEnd =
set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());

for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:

  • 求并集的两个集合必须的有序序列
  • 目标容器开辟空间需要两个容器相加
  • set_union返回值既是并集中最后一个元素的位置

set_difference

功能描述:

  • 求两个集合的差集

函数原型:

  • set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);

    // 求两个集合的差集

    // 注意:两个集合必须是有序序列

    // beg1 容器1开始迭代器
    // end1 容器1结束迭代器
    // beg2 容器2开始迭代器
    // end2 容器2结束迭代器
    // dest 目标容器开始迭代器

示例:

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
#include <vector>
#include <algorithm>

class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};

void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++) {
v1.push_back(i);
v2.push_back(i+5);
}

vector<int> vTarget;
//取两个里面较大的值给目标容器开辟空间
vTarget.resize( max(v1.size() , v2.size()));

//返回目标容器的最后一个元素的迭代器地址
cout << "v1与v2的差集为: " << endl;
vector<int>::iterator itEnd =
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;


cout << "v2与v1的差集为: " << endl;
itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
}

int main() {

test01();

system("pause");

return 0;
}

总结:

  • 求差集的两个集合必须的有序序列
  • 目标容器开辟空间需要从两个容器取较大值
  • set_difference返回值既是差集中最后一个元素的位置

STL常用算法汇总

STL(标准模板库)提供了大量通用算法,适用于所有容器(如 vectordequelistmap 等)。以下是常见的通用方法及其使用场景:

类别 常用函数 功能描述 时间复杂度 适用容器
非修改序列操作 std::find, std::count, std::search, std::equal 遍历容器元素,不修改内容(如查找、统计、比较)。 O(n) 所有序列容器(vector/list等)
修改序列操作 std::transform, std::replace, std::copy, std::fill, std::swap 修改容器元素值或位置(如替换、复制、填充、交换)。 O(n) 所有序列容器
排序与重排 std::sort, std::stable_sort, std::partial_sort 对序列排序(全排序、稳定排序、部分排序)。 O(n log n) vector, deque
二分法相关 std::binary_search, std::lower_bound, std::upper_bound 在有序序列中高效查找元素位置。 O(log n) 已排序的vector/deque
合并与分割 std::merge, std::inplace_merge, std::partition 合并两个有序序列或按条件分割元素。 O(n) vector, deque
最小/最大操作 std::min_element, std::max_element, std::minmax_element 查找最小、最大或极值元素。 O(n) 所有序列容器
数值运算 std::accumulate, std::inner_product, std::adjacent_difference 执行数值计算(求和、内积、相邻差值)。 O(n) vector, array
排列组合 std::next_permutation, std::prev_permutation 生成下一个/前一个排列组合(常用于全排列问题)。 O(n) vector, string
集合操作(有序) std::set_union, std::set_intersection, std::set_difference 对两个有序序列执行集合运算(并集、交集、差集)。 O(n + m) 已排序的vector/deque
堆操作 std::make_heap, std::push_heap, std::pop_heap 构建和维护堆结构(用于优先队列)。 O(n) 建堆, O(log n) 操作 vector

🔍 查找类算法

std::find

  • 用途:查找容器中是否存在某个元素。

  • 时间复杂度:O(n)

  • 示例:

    1
    2
    3
    4
    5
    std::vector<int> v = {1, 2, 3, 4};
    auto it = std::find(v.begin(), v.end(), 3);
    if (it != v.end()) {
    std::cout << "找到元素: " << *it << std::endl;
    }

std::find_if

  • 用途:查找满足特定条件的元素(通过 lambda 表达式定义条件)。

  • 示例:

    1
    2
    3
    4
    auto it = std::find_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
    if (it != v.end()) {
    std::cout << "找到偶数: " << *it << std::endl;
    }

std::count / std::count_if

  • 用途:统计容器中某个元素或满足条件的元素个数。

  • 示例:

    1
    2
    int cnt = std::count(v.begin(), v.end(), 2); // 统计值为2的元素个数
    int even_cnt = std::count_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; });
  • 用途:查找子序列是否存在。

  • 示例:

    1
    2
    3
    4
    5
    std::vector<int> sub = {2, 3};
    auto it = std::search(v.begin(), v.end(), sub.begin(), sub.end());
    if (it != v.end()) {
    std::cout << "找到子序列,起始位置索引: " << std::distance(v.begin(), it) << std::endl;
    }

🧮 数值计算类算法

std::accumulate

  • 用途:计算容器元素的总和(或自定义运算)。

  • 示例:

    1
    2
    3
    #include <numeric>
    int sum = std::accumulate(v.begin(), v.end(), 0); // 初始值为0
    int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>());

std::inner_product

  • 用途:计算两个容器的内积(逐元素相乘后求和)。

  • 示例:

    1
    2
    3
    std::vector<int> a = {1, 2, 3}, b = {4, 5, 6};
    int result = std::inner_product(a.begin(), a.end(), b.begin(), 0);
    // 结果: 1*4 + 2*5 + 3*6 = 32

🔄 修改类算法

std::transform

  • 用途:对容器元素进行转换(如加法、乘法等)。

  • 示例:

    1
    2
    std::vector<int> result(v.size());
    std::transform(v.begin(), v.end(), result.begin(), [](int x) { return x * 2; });

std::replace / std::replace_if

  • 用途:替换容器中的特定元素或满足条件的元素。

  • 示例:

    1
    2
    std::replace(v.begin(), v.end(), 2, 99); // 将所有2替换为99
    std::replace_if(v.begin(), v.end(), [](int x) { return x > 3; }, 0); // 替换大于3的元素为0

⏱️ 排序与搜索类算法

std::sort

  • 用途:对容器元素排序。

  • 时间复杂度:O(n log n)

  • 示例:

    1
    2
    std::sort(v.begin(), v.end()); // 升序排序
    std::sort(v.begin(), v.end(), std::greater<>()); // 降序排序
  • 用途:在有序容器中二分查找元素。

  • 前提:容器必须已排序。

  • 时间复杂度:O(log n)

  • 示例:

    1
    bool found = std::binary_search(v.begin(), v.end(), 3);

std::lower_bound / std::upper_bound

  • 用途:查找有序容器中第一个不小于/大于目标值的元素位置。

  • 示例:

    1
    2
    auto low = std::lower_bound(v.begin(), v.end(), 3); // 找到第一个≥3的位置
    auto up = std::upper_bound(v.begin(), v.end(), 3); // 找到第一个>3的位置