STL相关

目录

1.STL初识

1.1STL的诞生

1.2 STL基本概念

1.3STL六大组件

1.4 STL中容器、算法、迭代器

1.5容器算法迭代器初识

1.5.1 Vector存放内置数据类型

1.5.2 Vector存放自定义数据类型

1.5.3 Vector容器嵌套容器

2. STL常用容器

2.1 string容器

2.1.1 string基本概念

2.1.2 string构造函数

2.1.3 string赋值操作

2.1.4 string字符串拼接

2.1.5 string查找和替换

2.1.6 string字符串比较

2.1.7 string字符读取

2.1.8 string插入和删除

2.1.9 string字串

2.2 vector容器

2.2.1 vector基本概念

vector与普通数组区别:

动态扩展:

2.2.2 vector构造函数

2.2.3 vector赋值操作

2.2.4 vector容量和大小

2.2.5 vector插入和删除

2.2.6 vector数据存取

2.2.7 vector互换容器

2.2.8 vector预留空间

2.3deque容器

2.3.1 deque容器基本概念

2.2.3 deque赋值操作

2.3.4 deque大小操作

2.3.5 deque插入和删除

2.3.6 deque数据存取

2.3.7 deque排序

2.5 stack容器

2.5.1 stack基本概念

2.5.1 stack常用接口

2.6 queue容器

2.6.1 queue容器基本概念

2.6.2 queue常用接口

 2.7 list容器

2.7.1 list基本概念

2.7.2 list构造函数

2.7.3 list赋值和交换

2.7.4 list大小操作

2.7.5 list插入和删除

2.7.6 ist数据存取

2.7.7 list反转和排序

2.8 set/multiset容器

2.8.1 set基本概念

2.8.2 set构建和赋值

2.8.3 set大小和交换

2.8.4 set插入和删除

2.8.5 set查找和统计

2.8.6 set和multiset区别

2.8.7 pair对组创建

2.8.8 set容器排序

2.9 map/multimap容器

2.9.1 map基本概念

2.9.2 map构造和赋值

2.9.3 map大小和交换

2.9.4 map插入和删除

2.9.5 map查找和统计

2.9.6 map容器排序

3. STL函数对象

3.1 函数对象

3.11 函数对象概念

3.2 谓词

3.2.1 谓词概念

3.3 内建函数对象

3.3.1 内建函数对象意义

3.3.2算数仿函数

3.3.3 关系仿函数

3.3.4 逻辑仿函数

4. STL常用算法

概述:

4.1 常用遍历算法

4.1.1 for_each

4.1.2 transform

4.2 常用查找算法

4.2.1 find

4.2.2 find_if

4.2.3 adjacent_find

4.2.4 binary_search

4.2.5 count

4.2.6 count_if

4.3 常用的排序算法

4.3.1 sort

4.3.2 random_shuffle

4.3.3 merge

4.3.4 reverse

4.4 常用的拷贝和替换算法

4.4.1 copy

4.4.2 replace

4.4.3 replace_if

4.4.4 swap

4.5 常用算数生成算法

4.5.1 accumulate

4.5.2 fill

4.6 常用集合算法

4.6.1 set_intersection

4.6.2 set_union

4.6.3 set_difference


1.STL初识


1.1STL的诞生

  • 长久以来,软件届就一直希望建立一种可重复利用的东西
  • C++的面向对象和泛型编程思想,目的就是复用性的提升
  • 大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作
  • 为了建立数据结构和算法的一套标准,诞生了STL

1.2 STL基本概念

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

1.3STL六大组件

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

  • 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。
  • 算法:常用的各种算法,如sort、find、copy、for_each等
  • 迭代器:扮演了容器与算法之间的胶合剂
  • 仿函数:行为类似函数,可作为算法的某种策略
  • 适配器:一种用来修饰容器或者仿函数或迭代器结构的东西。
  • 空间配置器:负责空间的配置与管理。

1.4 STL中容器、算法、迭代器

容器:置物之所也

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

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

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

​ 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置

​ 关联式容器:二叉树结构体,各元素之间没有严格上的物理上的顺序关系

算法:问题之解法也

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

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

质变算法:是指运算过程中会更改区间内元素的内容。例如拷贝、查找、删除等等

非质变算法:是指在运算过程中不会更改区间内的元素内容,例如查找、

计数、遍历、寻找极值等等

迭代器:容器和算法之间的的粘合剂

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

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

迭代器的使用非常类似于指针,初学阶段我们可以先理解迭代器为指针。

迭代器种类:


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

1.5容器算法迭代器初识

了解STL容器、算法、迭代器概念之后,我们利用代码感受STL的魅力

STL中最常用的容器为Vector,可以理解为数组,下面我们将学习如何向这个容器中插入数据、并遍历这个容器

1.5.1 Vector存放内置数据类型

容器:vector

算法:for_each

迭代器:vector::iterator

//vector容器存放内置的数据类型
#include<iostream>
#include<vector>
#include<algorithm>//标准算法的头文件
using namespace std;

void test01()
{
	//创建了一个vector容器,可以看作数组
	vector<int>v;//尖括号里是要操纵的数据类型,给容器起个名叫v
	//向容器中尾插数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	
	//通过迭代器来访问容器中的数据
    //声明两个迭代器,第一种遍历方式 
	vector<int>::iterator itBegin = v.begin();//起始迭代器,指向容器中第一个元素
	vector<int>::iterator itEnd = v.end();//结束迭代器,指向容器中最后一个元素的下一个位置
	while (itBegin != itEnd)
	{
		cout << *itBegin << endl;
		itBegin++;
	}

	//第二种遍历方式
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}


	//第三种遍历方式 利用STL提供遍历算法,先要包含算法的头文件#include<algorithm>

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

	for_each(v.begin(), v.end(), myPrint);


}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

1.5.2 Vector存放自定义数据类型

学习目标:vector中存放自定义数据类型,并打印输出

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>//标准算法的头文件
using namespace std;

//vector中存放自定义数据类型
class Person
{
public:
	Person(string name,int age )
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	string m_Name;
	int m_Age; 
};
void test01()
{
	vector<Person>v;
	Person p1("a1", 10);
	Person p2("a2", 10);
	Person p3("a3", 10);
	Person p4("a4", 10);
	Person p5("a5", 10);
	//向容器中添加数据
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);


	//遍历容器中的数据
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		//cout << "姓名:" << (*it).m_Name << "年龄:" << (*it).m_Age << endl;
		cout << "姓名:" << it->m_Name << "年龄:" << it->m_Age << endl;
	}
}

//存放自定义数据类型的指针
void test02()
{
	vector<Person*>v;
	Person p1("a1", 10);
	Person p2("a2", 10);
	Person p3("a3", 10);
	Person p4("a4", 10);
	Person p5("a5", 10);
	//向容器中添加数据
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	v.push_back(&p4);
	v.push_back(&p5);


	//遍历迭代器
	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" << (*it)->m_Name << "年龄:" << (*it)->m_Age << endl;
	}
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

1.5.3 Vector容器嵌套容器

学习目标:容器中嵌套容器,我们将所有数据进行遍历输出

(类似二维数组)

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
//容器嵌套容器

void test01()
{
	vector<vector<int>>v;
	//创建小容器
	vector<int>v1;
	vector<int>v2;
	vector<int>v3;
	vector<int>v4;

	//向小容器中添加数据
	for (int i = 0; i < 4; i++)
	{
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
		v4.push_back(i + 4);
	}
	//将小容器插入到大容器中
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);

	//通过大容器遍历所有数据
	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
	{
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			cout << *vit << " ";
		}
		cout << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2. STL常用容器

2.1 string容器

2.1.1 string基本概念

本质:

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

string和char*区别:

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

特点:
strint类内部封装了很多成员方法

例如;查找find,拷贝copy,删除delete,替换replace,插入insert

string管理char*所分配的内存,不用但是赋值越界和取值越界等,由类内部进行负责

2.1.2 string构造函数

构造函数原型

  • string()创建一个空的字符串
  • string(const char* s)使用字符串s初始化,相当于可以传一个C语言的字符串构造C++的字符串
  • string(const string& str)使用一个string对象初始化另一个string对象,相当于拷贝构造
  • string(int n,char c)使用n个字符c初始化
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//string的构造函数
void test01()
{
	string s1;//默认构造
	const char* str = "hellow world";//C语言风格的字符串
	string s2(str);//c++98的写法,C++11的可以用大括号
	cout << "s2:"<<s2 << endl;

	string s3(s2);//拷贝构造
	cout << "s3" << s3 << endl;

    string s4(10,'a');//初始化10个a组成一个字符串
    string s5(10,42);//42阿斯克码值对应的字符是'*',初始化10个'*'组成的字符串
    
    string s6(s5,10,3);//区间构造,把s5从第10个开始的3个字符初始化给s5;

}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

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

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

void test01()
{
	string str1;
	str1 = "hello world";
	cout << "str1=" << str1 << endl;

	string str2;
	str2 = str1;
	cout << "str2=" << str2 << endl;
	
	string str3;
	str3 = 'c';
	cout << "str3=" << str3 << endl;

	string str4;
	str4.assign("hello c艹");
	cout << "str4=" << str4 << endl;

	string str5;
	str5.assign("hello c++",5);
	cout << "str5=" << str5 << endl;
	
	string str6;
	str6.assign(str5);
	cout << "str6=" << str6 << endl;

	string str7;
	str7.assign(10, 'w');
	cout << "str7=" << str7 << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.1.4 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个字符连接到字符串结尾
 

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

void test01()
{
	string str1 = "你";
	str1 += "是伞兵";
	cout << "str1=" << str1<< endl;

	str1 += '?';
	cout << "str1=" << str1 << endl;

	string str2 = "zbc";
	str1 += str2;
	cout << "str1=" << str1 << endl;

	string str3 = "You";
	str3.append(" SB");
	cout << "str3=" << str3 << endl;

	str3.append("hahaha hahaha", 4);
	cout << "str3=" << str3 << endl;

	str3.append(str2);
	cout << "str3=" << str3 << endl;

	str3.append(str2, 0, 1);
	cout << "str3=" << str3 << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.1.5 string查找和替换

功能描述:

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

函数原型[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-deuNeOqD-1628485740292)(/images/C++提高编程.assets/image-20210729171841276.png)]

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//字符串的查找和替换
//查找
void test01()
{
	string str1 = "abcdefg";
	//找到返回下标,找不到返回-1
	int pos1 = str1.find("de");
	cout << "pos1=" << pos1 << endl;
	int pos2 = str1.find("z");
	cout << "pos2=" << pos2<< endl;

	pos1 = str1.rfind("ab");//rfind是从右往左查找,find是从左往右查找
	cout << "pos1=" << pos1 << endl;;
}
//替换
void test02()
{
	string str2 = "abcdef";
	str2.replace(1, 3, "1111");//从1号位置起,3个字符替换为1111
	cout << "str2=" << str2 << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

总结

  • find查找是从左往右,rfind从右往左
  • find找到字符串后返回查找的第一个字符位置,找不到返回1
  • replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串

2.1.6 string字符串比较

功能描述:
字符串之间的比较

比较方式:

字符串比较是按字符的ASCII码进行对比

=返回0     >返回1    <返回-1

函数原型

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//字符串比较
void test01()
{
	string str1 = "zello";
	string str2 = "hello";
	if (str1.compare(str2) == 0)
	{
		cout << "相等" << endl;
	}
	else if (str1.compare(str2) > 0)
	{
		cout << "str1大" << endl;
	}
	else
	{
		cout << "str2大" << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结
字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大。

2.1.7 string字符读取

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SrKIjkJE-1628485740294)(/images/C++提高编程.assets/image-20210729174333189.png)]

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

//string字符存取
void test01()
{
	string str1 = "hello";
	//通过[]访问单个字符
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1[i] << " ";
	}
	cout << endl;
	//通过at方式访问的单个字符
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1.at(i) << " ";
	}
	cout << endl;

	//修改单个字符
	str1[0] = 'z';
	cout << str1 << endl;

	str1.at(0) = 'x';
	cout << str1 << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结:

string字符串中单个字符存取有两种方式,利用[]或at

2.1.8 string插入和删除

功能描述

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

函数原型:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jYFjbc88-1628485740294)(/images/C++提高编程.assets/image-20210729201545792.png)]

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
//字符串 插入和删除
void test01()
{
	string str = "hello";
	//插入
	str.insert(1, "111");
	cout << "str = " << str << endl;

	//删除
	str.erase(1,3);
	cout << "str = " << str << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结
插入和删除的起始下标都是从0开始。

2.1.9 string字串

功能描述:
从字符串中获得想要的字串。

函数原型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hw1d7pQ2-1628485740294)(/images/C++提高编程.assets/image-20210729232821929.png)]

#include<iostream>
#include<string>
using namespace std;

//string求字串
void test01()
{
	string str = "abcdef";
	string subStr = str.substr(1, 3);
	cout << "subStr=" << subStr << endl;
}
//实用操作
void test02()
{
	string email = "zhangsan@qq.com";
	//从邮箱地址中获取用户名信息
	int pos = email.find("@");
	string usrName = email.substr(0, pos);
	cout << usrName << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

2.2 vector容器

2.2.1 vector基本概念

功能:

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

vector与普通数组区别:

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

动态扩展:

  • 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ignjesy-1628485740296)(/images/C++提高编程.assets/image-20210730104217790.png)]

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

2.2.2 vector构造函数

功能描述:

  • 创建vector容器

函数原型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuhUrNIf-1628485740296)(/images/C++提高编程.assets/image-20210730111800301.png)]

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;

void printVector(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

//vector容器构造
void test01()
{
	vector<int>v1;//默认构造 无参构造
    v1[0]=0;//错误,默认构造后容器里没有数据
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);

	//通过区间的方式进行构造
	vector<int>v2(v1.begin(), v1.end());
	printVector(v2);
	
	//n个elem方式构造
	vector<int>v3(10, 100);//10个100
	printVector(v3);

	//拷贝构造
	vector<int>v4(v3);
	printVector(v4);

    //指定一个数组,利用指针来构造
    int test[]={1,2,3,4,5};
    vector<int> v3(test,test+2);

//逆转的迭代器
cout<<"逆向输出 v3:"<<endl;
vector<int>::reverse_iterator rit=v3.rbegin();
for(;rit!=v3.rend();rit++)
{
    cout<<*rit<<endl;
}

int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.2.3 vector赋值操作

功能描述
给vector容器进行赋值

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CdS2nUuR-1628485740297)(/images/C++提高编程.assets/image-20210730113659471.png)]

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
//vector赋值
void PrintVector(vector<int>& v)
{
	for (vector<int>::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);
	}
	PrintVector(v1);

	//赋值 operator= 
	vector<int>v2;
	v2 = v1;
	PrintVector(v2);

	//assign
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());//闭 开
	PrintVector(v3);

	//n个elem方式赋值
	vector<int>v4;
	v4.assign(10, 100);//10个100
	PrintVector(v4);

    //利用指针赋值
    int test[]={1,2,3,4,5};
    v5.assign(test,test+3);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.2.4 vector容量和大小

功能描述
对vector容器的容量和大小操作

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dV1ftKBQ-1628485740299)(/images/C++提高编程.assets/image-20210730114744210.png)]

capacity (容量)大于等于size

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
//vector容器的容量和大小操作
void PrintVector(vector<int>& v)
{
	for (vector<int>::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);
	}
	PrintVector(v1);

	if (v1.empty())
	{
		cout << "空" << endl;
	}
	else
	{
		cout << "不空" << endl;
	}

	cout << "v1的容量=" << v1.capacity() << endl;
	cout << "v1的大小=" << v1.size() << endl;
	
	//重新指定大小
    v1.resize(15);//如果重新指定的比原来的个数多了,默认用0来填充新的位置
	v1.resize(15,100);//利用重载版本,可以指定默认填充值,第二个参数
	PrintVector(v1);
	v1.resize(5);
	PrintVector(v1);//如果重新指定的比原来短,超出的部分会删除掉
}
int main(void) 
{
	test01();
	system("pause");
	return 0;
}

2.2.5 vector插入和删除

功能描述
对vector容器进行插入、删除操作

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2X1kPc07-1628485740299)(/images/C++提高编程.assets/image-20210731111526154.png)]

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//vector容器的插入和删除
void PrintVector(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int>v1;
	
	//尾插法
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	v1.push_back(50);
	
	//遍历
	PrintVector(v1);

	//尾删
	v1.pop_back();
	PrintVector(v1);

	//插入
	v1.insert(v1.begin(), 100);
	PrintVector(v1);

	v1.insert(v1.begin(), 2, 1000);
	PrintVector(v1);

    v2.insert(v2.begin(),v1.begin(),v1.end())

	//删除 参数也是迭代器
	v1.erase(v1.begin());
	PrintVector(v1);

    //删掉多个元素
    v1.erase(v1.begin(),v1.begin()+3);

	//清空
	//v1.erase(v1.begin(), v1.end());
	v1.clear();
	PrintVector(v1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • 尾插——push_back
  • 尾删——pop_back
  • 插入——insert(位置迭代器)
  • 删除——erase(位置迭代器)
  • 清空——clear

2.2.6 vector数据存取

功能描述
对vector中的数据进行存取操作

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLtwOZGf-1628485740299)(/images/C++提高编程.assets/image-20210731122906662.png)]

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//vector容器 数据存取
void test01()
{

	vector<int>v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}	
	//利用[]访问数组中的元素
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	cout << endl;

	//利用at方式访问元素
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << " ";
	}
	cout << endl;
	
	//获取第一个元素
	cout << "第一个元素=" << v1.front() << endl;

	//获取最后一个元素
	cout << "最后一个元素=" << v1.back()<<endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • 除了用迭代器获取vector中元素,[]和at也可以
  • front返回容器第一个元素
  • back返回容器最后一个元素

2.2.7 vector互换容器

功能描述
实现两个容器内元素进行互换

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0LbHfVjl-1628485740299)(/images/C++提高编程.assets/image-20210803114214740.png)]

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//vector容器互换

void PrintVector(vector<int> &v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	vector<int>v1;
	cout << "交换前" << endl;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	PrintVector(v1);
	vector<int>v2;

	for (int i = 10; i > 0; i--)
	{
		v2.push_back(i);
	}
	PrintVector(v2);
	cout << "交换后" << endl;

	v1.swap(v2);

	PrintVector(v1);
	PrintVector(v2);
}


//实际 用途
//巧用swap可以收缩内存空间
void test02()
{
	vector<int>v;
	for (int i = 0; i < 10000; i++)
	{
		v.push_back(i);
	}

	cout << "容量" << v.capacity() << endl;
	cout << "大小" << v.size() << endl;
	cout <<  endl;
	v.resize(3);//重新指定大小
	cout << "容量" << v.capacity() << endl;
	cout << "大小" << v.size() << endl;


	//巧用swap收缩内存
	vector<int>(v).swap(v);
	cout << endl;
	cout << "容量" << v.capacity() << endl;
	cout << "大小" << v.size() << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

 总结
swap可以使两个容器互换,可以达到实用的收缩内存效果。

2.2.8 vector预留空间

功能描述
减少vector在动态内存扩容时的扩展次数

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LLKoYfHS-1628485740300)(/images/C++提高编程.assets/image-20210803120835805.png)]

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//vector容器 预留空间
void test01()
{
	vector<int>v1;
	int num = 0;//统计开辟次数
	int* p = NULL;
	for (int i = 0; i < 100000; i++)
	{
		v1.push_back(i);
		
		if (p != &v1[0])
		{
			p = &v1[0];
			num++;
		}
	}
	cout << num << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.2.9 清零操作

  

2.3deque容器

2.3.1 deque容器基本概念

功能:

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

deque与vector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低
  • deque相对而言,对头部的插入删除速度会比vector快
  • vector访问元素时的速度会比deque快,这和两者内部实现有关
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3audWTIL-1628485740301)(/images/C++提高编程.assets/image-20210804100635832.png)]

deque的内部工作原理

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUdu8fLd-1628485740301)(/images/C++提高编程.assets/image-20210804101120562.png)]

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

deque构造函数

功能描述

deque容器构造

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDUHnToW-1628485740302)(/images/C++提高编程.assets/image-20210804101221795.png)]

#include<iostream>
#include<deque>
using namespace std;
void PrintDeque(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	PrintDeque(d1);

	deque<int>d2(d1.begin(), d1.end());
	PrintDeque(d2);

	deque<int>d3(10, 100);
	PrintDeque(d3);

	deque<int>d4(d3);
	PrintDeque(d4);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结
deque容器和vector容器的构造方式几乎一致,灵活使用即可。

2.2.3 deque赋值操作

功能描述
给deque容器进行赋值

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3wtS2n6m-1628485740302)(/images/C++提高编程.assets/image-20210804111712060.png)]

#include<iostream>
#include<deque>
using namespace std;
void PrintDeque(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	PrintDeque(d1);

	//operator=赋值
	deque<int>d2;
	d2 = d1;
	PrintDeque(d2);

	//assign赋值
	deque<int>d3;
	d3.assign(d1.begin(),d1.end());
	PrintDeque(d3);

	deque<int>d4;
	d4.assign(10, 100);
	PrintDeque(d4);

    //swap互换
    v4.swap(v3);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.3.4 deque大小操作

功能描述
对deque容器的大小进行操作

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SbaOE9tz-1628485740303)(/images/C++提高编程.assets/image-20210804112658313.png)]

#include<iostream>
#include<deque>
using namespace std;
void PrintDeque(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	PrintDeque(d1);
	if (d1.empty())
	{
		cout<<"空"<<endl;
	}
	else
	{
		cout<<"不空"<<endl;
	}
	//deque容器没有容量概念
	cout << "大小" << d1.size() << endl;

	//重新指定大小,并填充
	d1.resize(15,1);
	PrintDeque(d1);

	d1.resize(5);
	PrintDeque(d1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • deque没有容量概念
  • 判断是否为空——empty
  • 返回元素个数——size
  • 重新指定个数——resize

2.3.5 deque插入和删除

功能描述
向deque容器中插入和删除数据

函数原型
两端插入操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zSJBiLdj-1628485740304)(/images/C++提高编程.assets/image-20210804115946422.png)]

指定位置操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ic3jd0QE-1628485740304)(/images/C++提高编程.assets/image-20210804120000708.png)]

#include<iostream>
#include<deque>
using namespace std;
void PrintDeque(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
//两端操作
void test01()
{
	deque<int>d1;
	//尾插
	d1.push_back(10);
	d1.push_back(20);

	//头插
	d1.push_front(100);
	d1.push_front(200);

	PrintDeque(d1);
	//尾删
	d1.pop_back();
	PrintDeque(d1);

	//头删
	d1.pop_front();
	PrintDeque(d1);

//使用迭代器遍历删除,指定删除值为4的元素,见奇牛deque插入和删除
for(deque<int>::iterator it=d1.begin();it!=d1.end();)
{
    if(*it==4)
        it=d1.erase(it);
    else
        {
           cout<<*it;
            it++;
        }
}    

void test02()
{
	deque<int>d2;
	//尾插
	d2.push_back(10);
	d2.push_back(20);

	//头插
	d2.push_front(100);
	d2.push_front(200);

	PrintDeque(d2);

	//insert插入
	d2.insert(d2.begin(), 1000);//有返回值,返回新数据的位置
	PrintDeque(d2);

	d2.insert(d2.begin(), 2,10000);//无返回值
	PrintDeque(d2);

	//按照区间进行插入
	deque<int>d3;
	d3.push_back(1);
	d3.push_back(2);
	d3.push_back(3);

	d2.insert(d2.begin(), d3.begin(), d3.end());//无返回值
    d2.insert(d2.begin(), d3.rbegin(), d3.rend());//逆序插入
	PrintDeque(d2);
}

void test03()
{


	deque<int>d4;
	//尾插
	d4.push_back(10);
	d4.push_back(20);

	//头插
	d4.push_front(100);
	d4.push_front(200);

	PrintDeque(d4);

	//删除
	deque<int>::iterator it = d4.begin();
	it++;
	d4.erase(it);//有返回值,返回下一数据的位置
	PrintDeque(d4);
	
	//按照区间方式删除
	d4.erase(d4.begin(), d4.end());//有返回值,返回下一数据的位置
	PrintDeque(d4);
	//清空
	d4.clear();
	PrintDeque(d4);
}
int main(void)
{
	test01();
	test02();
	test03();
	system("pause");
	return 0;
}

总结

  • 插入和删除提供的位置是迭代器!
  • 尾插——push_back
  • 尾删——pop_back
  • 头插——push_front
  • 头删——pop_front

2.3.6 deque数据存取

功能描述
对deque中的数据的存取操作

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-92OCZnOe-1628485740305)(/images/C++提高编程.assets/image-20210804122554441.png)]

#include<iostream>
#include<deque>
using namespace std;
//常量迭代器
void PrintDeque1(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.cbegin(); it != d.cend(); it++)
	{
		cout << *it << " ";
        (*it)++;//错误,常量迭代器,不可以做修改值的操作
	}
	cout << endl;
}
//普通迭代器
void PrintDeque1(const deque<int>& d)
{
	for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
        (*it)++;//正确
	}
	cout << endl;
}
//逆转的迭代器
void PrintDeque1(const deque<int>& d)
{
	for (deque<int>::reverse_iterator it = d.rbegin(); it != d.rend(); it++)
	{
		cout << *it << " ";
        (*it)++;//正确
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	for (int i = 0; i < 3; i++)
	{
		d1.push_back(i);
	}
	d1.push_front(100);
	d1.push_front(200);
	d1.push_front(300);
	
	//通过[]方式访问元素
	for (int i = 0; i < d1.size(); i++)
	{
		cout << d1[i] << " ";
	}
	cout << endl;
	//通过at方式访问元素
	for (int i = 0; i < d1.size(); i++)
	{
		cout << d1.at(i) << " ";
	}
	cout << endl;

	cout << "第一个元素=" << d1.front() << endl;
	cout << "最后一个元素=" << d1.back() << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.3.7 deque排序

功能描述
利用算法实现对deque容器进行排序

算法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MV3liTLO-1628485740305)(/images/C++提高编程.assets/image-20210804170324824.png)]

#include<iostream>
#include<deque>
#include<algorithm>//标准算法头文件
using namespace std;
void PrintDeque(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	deque<int>d1;
	d1.push_back(10);
	d1.push_back(20);
	d1.push_back(30);
	d1.push_front(100);
	d1.push_front(200);
	d1.push_front(300);

	PrintDeque(d1);
	
	//排序-默认升序
	//对于支持随机访问的迭代器容器,都可以用sort算法对其进行排序
	//vector容器也可以利用sort进行排序
	cout << "排序后" << endl;
	sort(d1.begin(), d1.end());
	PrintDeque(d1);
	
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.5 stack容器

2.5.1 stack基本概念

概念:
stack是一种先进后出的数据结构,它只有一个出口。

stack是基于deque容器而实现的容器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q9W5ONBE-1628485740306)(/images/C++提高编程.assets/image-20210805112418931.png)]

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

栈可以判断容器是否为空。

栈可以返回元素个数。

栈中进入数据——进栈。

栈中弹出数据——出栈。

注意:stack和queue容器都没有迭代器,因此不能利用迭代器访问,如何访问(输出)stack内元素

//输出容器内所有元素
stack<int> s;
s.push(1);
s.push(2);
while(!s.empty())
{
    cout<<s.top();
    s.pop();//栈顶元素出栈
}

stack默认使用deque存储元素

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int main()
{
    stack<int> s;//默认使用deque存储元素
    stack<int,vector<int>> s;//可以自己指定其他的例如vector,list,需要写对应头文件,queue不可以
}

2.5.1 stack常用接口

功能描述:

栈容器常用的对外接口。

构造函数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fn1JoBw7-1628485740307)(/images/C++提高编程.assets/image-20210805113149343.png)]
赋值操作:

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lqYO1PES-1628485740308)(/images/C++提高编程.assets/image-20210805113158783.png)]


数据存取:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9T1qngni-1628485740308)(/images/C++提高编程.assets/image-20210805113211347.png)]

也可以利用top()修改栈顶元素的值

s.top()=88;


大小操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q14qPgnq-1628485740309)(/images/C++提高编程.assets/image-20210805113223145.png)]


2.6 queue容器

2.6.1 queue容器基本概念

概念
Queue是一种先进先出的数据结构,它有两个出口。

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GmmdYwZx-1628485740309)(/images/C++提高编程.assets/image-20210805114017941.png)]

只有队头和队尾能被外界访问,因此不允许有遍历行为。

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

队列中进入数据——入队。

队列中出数据——出队。

注意

默认queue是基于deque容器而实现的容器

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
int main()
{
    queue<int> s;//默认使用deque存储元素
    queue<int,vector<int>> s;//可以自己指定其他的例如list,需要写对应头文件,vector不可以
}

2.6.2 queue常用接口

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

构造函数

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dEtgODps-1628485740310)(/images/C++提高编程.assets/image-20210805114753060.png)]

赋值操作 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IiJCjjwm-1628485740310)(/images/C++提高编程.assets/image-20210805114809771.png)]

数据存取

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zITIlRU3-1628485740311)(/images/C++提高编程.assets/image-20210805114820944.png)]

大小操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5uZl9Zb-1628485740312)(/images/C++提高编程.assets/image-20210805114832232.png)]

#include<iostream>
#include<queue>
#include<string>
using namespace std;
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};
void test01()
{
	queue<Person>q;

	Person p1("s1", 1);
	Person p2("s2", 2);
	Person p3("s3", 3);
	Person p4("s4", 4);

	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);
	cout << "大小=" << q.size() << endl;
	while (!q.empty())
	{
		cout << q.front().m_Name <<" " << q.front().m_Age << endl;
		q.pop();
	}
	cout << "大小=" << q.size() << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.6.3 优先队列

优先队列 它的入队顺序没有变化,但是出队的顺序是根据优先级的高低来决定的。优先级高的优先出队。

  1. 最大值优先级队列、最小值优先级队列  
  2. 用来开发一些特殊的应用
  3. #include <queue>
#include <queue>
#include <iostream>
#include <list>
#include <vector>
#include <deque>
#include <set>

using namespace std;

int main(void) {
	
	//priority_queue<int>   pqA;//默认情况下是值越大,优先级越大
	//priority_queue<int, vector<int>, greater<int>> pqA;  //使用 vector 值越小,优先级越大
	priority_queue<int, deque<int>, greater<int>> pqA;  //使用deque 值越小,优先级越大
	//priority_queue<int, list<int>, greater<int>> pqA;     //不可以使用list,不兼容

	pqA.push(1);
	pqA.push(2);
	pqA.push(3);
	pqA.push(3);
	pqA.push(4);
	pqA.push(5);
	pqA.push(3);

	while(!pqA.empty()){
		cout<<pqA.top()<<" ";//读取队首的元素,但元素不出列,优先队列没有front(),back()操作
		pqA.pop();           //出队列
	}

	cout<<endl;

	system("pause");
	return 0;

 2.7 list容器

list没有data()函数

list反向输出

void PrintList(const list<SInfo>& L)
{
	for (list<SInfo>::const_iterator it = L.end(); it != L.begin(); )
	{
		it--;
		cout << it->nNumb << " ";
	}
	cout << endl;
}

2.7.1 list基本概念

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

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

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

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

SLT中的链表是一个双向循环链表。

注意事项: list不可以随机存取元素,所以不支持at()函数与[ ]操作符,可以对迭代器执行++操作,不可以做加减操作比如+1或+2或+3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ulMzROCU-1628485740313)(/images/C++提高编程.assets/image-20210805120915479.png)]

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。vector的内存空间是预先分配的·,有capacity()方法,list没有提前分配空间,不存在capacity()方法

list的优点:

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

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

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

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

2.7.2 list构造函数

功能描述
创建list容器

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bNQTg3fc-1628485740314)(/images/C++提高编程.assets/image-20210805162828155.png)]

#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	PrintList(l1);

	list<int>l2(l1.begin(), l1.end());
	PrintList(l2);


	list<int>l3(l2);
	PrintList(l3);
	
	list<int>l4(10, 100);
	PrintList(l4);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.7.3 list赋值和交换

功能描述
给list容器进行赋值,以及交换list容器。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8btGZE19-1628485740314)(/images/C++提高编程.assets/image-20210805163941142.png)]

 #include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;

	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	PrintList(l1);

	list<int>l2;
	l2 = l1;//operator=
	PrintList(l2);

	list<int>l3;
	l3.assign(l2.begin(), l2.end());
	PrintList(l3);

	list<int>l4;
	l4.assign(10, 100);
	PrintList(l4);

}
void test02()
{
	list<int>l5;

	l5.push_back(1);
	l5.push_back(2);
	l5.push_back(3);
	l5.push_back(4);

	list<int>l6;
	l6.push_back(4);
	l6.push_back(3);
	l6.push_back(2);
	l6.push_back(1);
	cout << "交换前" << endl;
	PrintList(l5);
	PrintList(l6);

	l5.swap(l6);
	cout << "交换后" << endl;
	PrintList(l5);
	PrintList(l6);
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

2.7.4 list大小操作

功能描述
对list容器的大小进行操作。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0R1rjLj-1628485740315)(/images/C++提高编程.assets/image-20210805165335377.png)]

#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	
	PrintList(l1);

	if (l1.empty())
	{
		cout << "空" << endl;
	}
	else
	{
		cout << "不空" << endl;
		cout << "元素个数=" << l1.size()<<endl;
	}
	
	//重新指定大小
	l1.resize(10, 1000);
	PrintList(l1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.7.5 list插入和删除

功能描述
对list容器进行数据的插入和删除

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a2XnhA9X-1628485740315)(/images/C++提高编程.assets/image-20210805170349557.png)]

#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;
	//尾插
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	//头插
	l1.push_front(10);
	l1.push_front(20);

	PrintList(l1);

	//尾删
	l1.pop_back();
	PrintList(l1);
    //头删
	l1.pop_front();
	PrintList(l1);

	//insert插入,插入第一个位置
    L.insert(L.begin(),1000);
    //insert插入,插入第二个位置,其他位置也类似
	list<int>::iterator it = l1.begin();
	it++;
	l1.insert(it, 1000);
	PrintList(l1);

	//删除
	//用的时候指定it
	it = l1.begin();
	l1.erase(++it);
	PrintList(l1);

	//移除
	l1.push_back(1000);
	l1.push_back(1000);
	l1.push_back(1000);
	PrintList(l1);

    //remove
	l1.remove(1000);//删除所有匹配的元素

    for(list<int>::iterator it=l1.begin();it!=l1.end();)
{
    if(*it==4)
        it=l1.erase(it);
    else
        {
          
            it++;
        }
}    

	PrintList(l1);


	//清空
	l1.clear();
	PrintList(l1);
}

int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.7.6 ist数据存取

功能描述
对list容器中数据进行存储。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tjixJ6PQ-1628485740315)(/images/C++提高编程.assets/image-20210805172011129.png)]

front()和back()返回的是引用所以可以做左值 

 思考:List为什么不能用中括号[ ]和at()访问里面的数据?因为List是一个链表,链表存储的方式不是连续的空间,而且List的迭代器也不支持随机访问

#include<iostream>
#include<list>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);

	//list中不可以用[]访问容器中的元素
	//at()也不行
	//因为List本质是链表,不是用连续的线性空间存储数据,迭代器也是不支持随机访问的

	cout << "第一个元素=" << l1.front() << endl;
	cout << "最后一个元素=" << l1.back() << endl;

    l1.front()=11;
    l1.back()=12;//允许做这样的修改操作

	//验证迭代器是不支持随机访问的
	list<int>::iterator it = l1.begin();
	it++;//支持++ --  双向
	it--;
	//it = it+1;不行——不支持随机访问

}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.7.7 list反转和排序

功能描述
将容器中的元素反转,以及将容器中的数据进行排序。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ADbZW3UX-1628485740316)(/images/C++提高编程.assets/image-20210805172922727.png)]

#include<iostream>
#include<list>
#include<algorithm>
using namespace std;
void PrintList(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	list<int>l1;
	l1.push_back(1);
	l1.push_back(2);
	l1.push_back(3);
	l1.push_back(4);
	
	cout << "反转前" << endl;
	PrintList(l1);

	//反转
	cout << "反转后" << endl;
	l1.reverse();
	PrintList(l1);
}

bool myCompare(int v1, int v2)
{
	//降序 第一个数>第二个数
	return v1 > v2;
}

//排序
void test02()
{
	list<int>l2;
	l2.push_back(20);
	l2.push_back(10);
	l2.push_back(50);
	l2.push_back(30);
	l2.push_back(40);
	cout << "排序前" << endl;
	PrintList(l2);

	//所有不支持随机访问迭代器的容器不可以用标准算法
	//不支持随机访问迭代器的容器,内部会提供对应的一些算法

	cout << "排序后" << endl;
    sort(l2.begin(),l2.end());//运行错误,原因:所有不支持随机访问迭代器的容器不可以用标准算法,即不可以用全局函数
    //默认排序
	l2.sort();
    //运行成功,不支持随机访问迭代器的容器,内部会提供对应的一些算法,即可以用成员函数
    //默认排序规则:从小到大,升序序列
	PrintList(l2);

	l2.sort(myCompare);//降序
	PrintList(l2);
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

结构体类型进行排序需要运算符重载 

//默认排序
#include <iostream>
#include <list>
using namespace std;
struct SInfo
{
	int nNumb;
	char sName[20];
	float fSala;
};
void PrintList(const list<SInfo>& L)
{
	for (list<SInfo>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << it->nNumb << " ";
	}
	cout << endl;
}
bool operator<(const SInfo& v1, const SInfo& v2)
{
	return v1.nNumb < v2.nNumb;
}
int main()
{
	list<SInfo> t1;
	t1.push_back({ 101, "张三", 22 });
	t1.push_back({ 104, "张三", 22 });
	t1.push_back({ 103, "张三", 22 });
	t1.sort();
	PrintList(t1);
}
//指定规则的排序,同时完成了从大到小的排序以及结构体的排序
#include <iostream>
#include <list>
using namespace std;
struct SInfo
{
	int nNumb;
	char sName[20];
	float fSala;
};
void PrintList(const list<SInfo>& L)
{
	for (list<SInfo>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << it->nNumb << " ";
	}
	cout << endl;
}
bool byNumb(const SInfo& v1, const SInfo& v2)
{
	return v1.nNumb > v2.nNumb;
}
int main()
{
	list<SInfo> t1;
	t1.push_back({ 101, "张三", 22 });
	t1.push_back({ 104, "张三", 22 });
	t1.push_back({ 103, "张三", 22 });
	t1.sort(byNumb);
	PrintList(t1);
}

2.8 set/multiset容器

2.8.1 set基本概念

简介
所有元素都会在插入时被自动排序。

本质
set/multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别

  •  set中元素插入过程是按排序规则插入,所以不能指定插入位置,因为本身基于是排序的,无法灵活的增加和减少容器大小,因为不涉及resize()方法
  • set不可以直接存取元素。(不可以使用at.(pos)与[]操作符)。
  • multiset与set的区别:set支持唯一键值,每个元素值只能出现一次;而multiset中同一值可以出现多次
  • 不可以直接修改set或multiset容器中的元素值,因为该类容器是自动排序的。如果希望修改一个元素值,必须先删除原有的元素,再插入新的元素
  • 头文件 #include <set> 

2.8.2 set构建和赋值

功能描述

创建set容器以及赋值。

构造

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lCpzU4zr-1628485740316)(/images/C++提高编程.assets/image-20210806172851153.png)]

赋值

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C7E9K0o7-1628485740317)(/images/C++提高编程.assets/image-20210806172858687.png)]

#include<iostream>
#include<set>
using namespace std;

void PrintSet(set<int> &s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test01()
{
	set<int>s1;
	//只有insert,自动排序,不能插入重复数据
	s1.insert(30);
	s1.insert(20);
	s1.insert(10);
	s1.insert(40);

	PrintSet(s1);

	set<int>s2(s1);

	PrintSet(s2);

	set<int>s3;
	s3 = s2;
	PrintSet(s3);

}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • set容器插入数据时用insert
  • set容器插入的数据会自动排序

2.8.3 set大小和交换

功能描述
统计set容器大小以及交换set容器。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXQR41p0-1628485740317)(/images/C++提高编程.assets/image-20210806173127646.png)]

#include<iostream>
#include<set>
using namespace std;

void PrintSet(set<int> &s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
	cout << *it << " ";
}
cout << endl;
}

void test01()
{
	set<int>s1;
	s1.insert(10);
	s1.insert(20);
	s1.insert(30);
	s1.insert(40);

	PrintSet(s1);
	
	if (s1.empty())
	{
		cout << "空" << endl;
	}
	else
	{
		cout << "不空" << endl;
		cout << "大小:" << s1.size() << endl;
	}
	
}

void test02()
{
	set<int>s2;
	set<int>s3;

	s2.insert(100);
	s2.insert(200);
	s2.insert(300);

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


	
	cout << "交换前:" << endl;
	PrintSet(s2);
	PrintSet(s3);
	s2.swap(s3);
	cout << "交换后:" << endl;

	PrintSet(s2);
	PrintSet(s3);
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

2.8.4 set插入和删除

功能描述
set容器进行插入数据和删除数据

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f8MJsOXv-1628485740318)(/images/C++提高编程.assets/image-20210806173813649.png)]

#include<iostream>
#include<set>
using namespace std;

void PrintSet(set<int> &s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
	cout << *it << " ";
}
cout << endl;
}
void test01()
{
	set<int>s1;
	
	s1.insert(2);
	s1.insert(1);
	s1.insert(3);
	s1.insert(4);
    s1.insert(4);//错误,不能插入重复元素
    //如何验证是否插入成功
    pair<set<int>::iterator, bool> ret = s1.insert(i);
		if(ret.second){
			cout<<"插入 "<<i<<" 成功!"<<endl;
		}else {
			cout<<"插入 "<<i<<" 失败!"<<endl;
		}


	PrintSet(s1);

	s1.erase(s1.begin());//删掉的是10,因为是按顺序排列的,排在第一位的是10
	PrintSet(s1);

	s1.erase(3);
	PrintSet(s1);
	
	s1.erase(s1.begin(), s1.end());
	PrintSet(s1);

	s1.clear();
	PrintSet(s1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.8.5 set查找和统计

功能描述
对set容器进行查找数据以及统计数据

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0NpQcorT-1628485740318)(/images/C++提高编程.assets/image-20210806174340081.png)]

  • set.lower_bound(elem);  //返回第一个>=elem元素的迭代器。
  • set.upper_bound(elem);    //  返回第一个>elem元素的迭代器。
  • set.equal_range(elem);         //返回容器中与elem相等的上下限的两个迭代器。上限是闭区间,下限是开区间,如[beg,end)。以上函数返回两个迭代器,而这两个迭代器被封装在pair中。如1,2,3,4,5 如果elem=3,则返回[3 ,4 ),包含了1个3,即等于这个元素的起始位置,结束的位置刚好是不等于这个元素的边界位置,如果是multiset.equal_range(elem),如1,2,3,3,3,4,5,返回[3, 4),包含了三个3

#include<iostream>
#include<set>
using namespace std;

void PrintSet(set<int> &s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
	cout << *it << " ";
}
cout << endl;
}
void test01()
{
	set<int>s1;
	s1.insert(1);
	s1.insert(2);
	s1.insert(3);
	s1.insert(4);

	set<int>::iterator pos = s1.find(3);

	if (pos != s1.end())
	{
		cout << "找到" << *pos << endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

	int num = s1.count(3);
    cout << num << "个" << endl;
	//对于set而言 统计结果 0 或 1,因为无重复

    s1.insert(3);
    s1.insert(3);
//即使插入多个3,统计结果依然只要1个,因为不允许重复
    int num = s1.count(3);
	cout << num << "个" << endl;


    pair< set<int>::iterator, set<int>::iterator > ii= s1.equal_range(5);  
    cout<<” equal_range(5)返回的第一个迭代器的值”<<*(ii.first)<<endl;
    cout<<” equal_range(5)返回的第二个迭代器的值”<<*(ii.second)<<endl;

}


int main(void)
{
	test01();

	system("pause");
	return 0;
}

总结

  • 查找——find(返回的是迭代器)
  • 统计——count(对于set,结果为0或者1)

2.8.6 set和multiset区别

学习目标
掌握set和multiset的区别

区别

  • set不可以插入重复数据,而multiset可以
  • set插入数据的同时会返回插入结果,表示插入是否成功
  • multiset不会检测数据,因此可以插入重复数据
#include<iostream>
#include<set>
using namespace std;


void PrintMultiSet(multiset<int>& ms)
{
	for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	set<int>s1;
	pair<set<int>::iterator,bool>ret = s1.insert(10);
	
	if (ret.second)//.second表示插入成功与否
	{
		cout << "插入成功" << endl;
	}
	else
	{
		cout << "插入失败" << endl;
	}

	//第二次
	ret = s1.insert(10);

	if (ret.second)//此时插入不成功,因为不能重复
	{
		cout << "插入成功" << endl;
	}
	else
	{
		cout << "插入失败" << endl;
	}

	multiset<int>ms;

	ms.insert(10);
	ms.insert(10);

	PrintMultiSet(ms);

}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.8.7 pair对组创建

功能描述
成对出现的数据,利用对组可以返回两个数据。

两种创建方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XLZ6PYSA-1628485740320)(/images/C++提高编程.assets/image-20210806180053425.png)]

#include<iostream>
#include<string>
using namespace std;


void test01()
{
	//第一种
	pair<string, int>p("Tom", 11);
	cout << p.first <<" "<< p.second << endl;

	//第二种
	pair<string, int>p2 = make_pair("Jerry", 12);
	cout << p2.first << " " << p2.second << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.8.8 set容器排序

学习目标
set容器默认排序规则为从小到大,掌握如何改变排序规则。

主要技术点
利用仿函数,可以改变排序顺序。

内置类型

#include<iostream>
#include<set>
using namespace std;


class MyCompare
{
public:
	//vs2019结尾加const
	bool operator()(int v1,int v2)const
	{
		return v1 > v2; 
	}
};

void test01()
{
	set<int,MyCompare>s1;

	//set容器要在还没插数据之前对排序进行改变


	s1.insert(10);
	s1.insert(20);
	s1.insert(30);
	s1.insert(40);

	for (set<int,MyCompare>::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

自定义类型

#include<iostream>
#include<set>
#include<string>
using namespace std;



class Person
{
public:

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


class Mycompare
{
public:
	bool operator()(const Person& p1, const Person& p2)const
	{
		return p1.m_Age > p2.m_Age;
	}
};


void test01()
{
	set<Person, Mycompare>s1;
	Person p1("s1",11);
	Person p2("s2",22);
	Person p3("s3",33);
	Person p4("s4",44);

	s1.insert(p1);
	s1.insert(p2);
	s1.insert(p3);
	s1.insert(p4);
	for (set<Person, Mycompare>::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << it->m_Name << " " << it->m_Age << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • 利用仿函数可以指定set容器的排序规则。

  • 对于自定义数据类型,set必须指定排序规则才可以插入数据。

2.9 map/multimap容器

2.9.1 map基本概念

简介

  • map中所有元素都是pair
  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
  • 所有元素都会根据元素的键值自动排序
  • map中key值是唯一的。集合中的元素按一定的顺序排列。元素插入过程是按排序规则插入,所以不能指定插入位置。因为本身基于是排序的,无法灵活的增加和减少容器大小,因为不涉及resize()方法
  • map可以直接存取key所对应的value,支持[]操作符,如map[key]=value。
  • map底层的具体实现是采用红黑树变体的平衡二叉树的数据结构。在插入操作、删除和检索操作上比vector快很多。

multimap与map的区别

map支持唯一键值,每个键只能出现一次;而multimap中相同键可以出现多次。multimap不支持[]操作符。

本质

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

优点

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

区别
map和multimap区别

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

2.9.2 map构造和赋值

功能描述
对map容器进行构造和赋值操作。

函数原型
构造

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XUIYliOZ-1628485740320)(/images/C++提高编程.assets/image-20210806184724565.png)]

赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-to4GznrY-1628485740321)(/images/C++提高编程.assets/image-20210806184745670.png)]

#include<iostream>
#include<map>
using namespace std;

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

void test01()
{
	map<int, int>m1;
	m1.insert(pair<int, int>(1, 10));
	m1.insert(pair<int, int>(2, 20));
	m1.insert(pair<int, int>(3, 30));
	m1.insert(pair<int, int>(4, 40));

	PrintMap(m1);

	map<int, int>m2(m1);
	PrintMap(m1);

	map<int, int>m3;
	m3 = m2;
	PrintMap(m3);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结
map中所有元素都是成对出现,插入数据时要使用对组。

2.9.3 map大小和交换

功能描述
统计map容器大小以及交换map容器

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TnBqZ04T-1628485740321)(/images/C++提高编程.assets/image-20210806185502487.png)]

#include<iostream>
#include<map>
using namespace std;

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

void test01()
{


	map<int, int>m1;
	m1.insert(pair<int, int>(1, 10));
	m1.insert(pair<int, int>(2, 20));
	m1.insert(pair<int, int>(3, 30));
	m1.insert(pair<int, int>(4, 40));

	PrintMap(m1);

	if (m1.empty())
	{
		cout << "空" << endl;
	}
	else
	{
		cout << "不空" << endl;
		cout << "大小=" << m1.size() << endl;
	}


	map<int, int>m2;
	m2.insert(pair<int, int>(10, 1));
	m2.insert(pair<int, int>(20, 2));
	m2.insert(pair<int, int>(30, 3));
	m2.insert(pair<int, int>(40, 4));

	cout << "交换前" << endl;
	PrintMap(m1);
	PrintMap(m2);

	cout << "交换后" << endl;

	m1.swap(m2);
	PrintMap(m1);
	PrintMap(m2);

}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.9.4 map插入和删除

功能描述:
map容器进行插入数据和删除数据

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JpcEImar-1628485740321)(/images/C++提高编程.assets/image-20210807110709847.png)]

#include<iostream>
#include<map>
using namespace std;

void PrintMap(map<int, int>& m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key=" << it->first << " " << "value=" << it->second 
<< endl;
	}
	cout << endl;
}
void test01()
{
	map<int, int>m1;
	//第一种
	m1.insert(pair<int, int>(1, 10));
    m1.insert(pair<int, int>(1, 11));//插入失败,如果键存在,则不会插入失败,不会覆盖原值,第四种插入方式即使键存在,可以覆盖原值
	//第二种
	m1.insert(make_pair(2, 20));
	//第三种
	m1.insert(map<int, int>::value_type(3, 30));
	//第四种
	m1[4] = 40;//不建议[]方式插入,但可以用来按照key访问到value,key不存在会自动创建,
所以应该确定存在再访问
    //	第四种方法非常直观,但碰到相同的键时会进行覆盖操作。比如插入key 为4的键值时,
先在mapStu中查找主键为4的项,若不存在,则将一个键为4,值为默认初始化值的对组插入到mapStu中,
然后再将值修改成“赵六”。若发现已存在4这个键,则修改这个键对应的value。
	cout << m1[4] << endl;

    //string strName = m1[8];   //取值操作或插入操作,只有当m1存在8这个键时才是正确的取操作,否则会自动插入一个实例,键为8,值为默认构造时的初始化值。


    //判断插入是否成功,	前三种方法,采用的是insert()方法,该方法返回值为pair<iterator,bool>
    pair<map<int, string>::iterator,bool> ret = m1.insert(pair<int, string>(1, "张     三"));
	if(ret.second==true){
		cout<<"插入成功! value: "<<(*(ret.first)).second<<endl;
	}else {
		cout<<"插入失败!"<<endl;
	}


	PrintMap(m1);

	m1.erase(m1.begin());
	PrintMap(m1);
	
	m1.erase(3);//按照key删除
    map<int,string,great<int>>::size_type ret=m1.erase(5);//erase(elem)的返回值是删除这个元素的个数
    cout<<ret<<endl;
	PrintMap(m1);

	m1.erase(m1.begin(), m1.end());
	PrintMap(m1);

    //删除数组指定的半闭半开的区间中特定的key对应的所有队组,map.erase(key_type *first, key_type *last)  ,见奇牛学院map删除
	
    int range[]={1,2,3,4}
    m1.erase(range+1,range+3);


	m1.clear();
	PrintMap(m1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.9.5 map查找和统计

功能描述
对map容器进行查找和数据以及统计数据

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nf7DjZP4-1628485740322)(/images/C++提高编程.assets/image-20210807113756573.png)]

#include<iostream>
#include<map>
using namespace std;

void PrintMap(map<int, int>& m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key=" << it->first << " " << "value=" << it->second << endl;
	}
	cout << endl;
}
void test01()
{
    //map的查找
	map<int, int>m1;
    m1.insert(pair<int, int>(1, 10));
	m1.insert(pair<int, int>(2, 20));
	m1.insert(pair<int, int>(3, 30));
    map<int, int>::iterator pos = m1.find(3);//返回迭代器
    if (pos != m1.end())
	{
		cout << "找到了" <<pos->first<<" "<<pos->second<< endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

	//map不允许插入重复key,0 or 1
	//multimap可以大于1,可以重复
	int num = m1.count(3);
	cout << num << endl;



	//multimap 的查找
	int count = mmapTeacher.count(101);
	multimap<int, string>::iterator mit = mmapTeacher.find(101);

	if(mit !=mmapTeacher.end()){//找到了
		//输出multimap 中的同一键的多个值

		//方法一 通过比较key ,循环判断   推荐使用
        for(; mit!=mmapTeacher.end(); mit++){
			if((*mit).first == 101){
				cout<<"mmapTeacher.find(101) = "<<(*mit).second<<endl;
			}else{
				break;
			}
		}

		//方法二 通过count计数来控制
		for(int i=0; i<count; i++, mit++){
				cout<<"mmapTeacher.find(101) = "<<(*mit).second<<endl;
		}
	}else {//没找到
		cout<<"找不到键值为101的键值对!"<<endl;
	}

	//equal_range 用法
	pair<multimap<int, string>::iterator, multimap<int, string>::iterator> mmiit = mmapTeacher.equal_range(101);
	
	//第一个迭代器, 对应begin
	if(mmiit.first != mmapTeacher.end()){
		cout<<"mmapTeacher.equal_range(101).begin ="<<(*mmiit.first).second<<endl;
	}
	 //第二个迭代器,对应end
	if(mmiit.second != mmapTeacher.end()){
		cout<<"mmapTeacher.equal_range(101).end ="<<(*mmiit.second).second<<endl;
	}


	for(map<int, string>::iterator it=mapStu.begin(); it!=mapStu.end(); it++){
		cout<<"key: "<<(*it).first << " value: "<<(*it).second <<endl;
	}

	system("pause");
	return 0;
}



}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

2.9.6 map容器排序

学习目标
map容器默认排序规则为按照key值进行从小到大排序,掌握如何改变排序规则。

主要技术点
利用仿函数,可以改变排序规则。

#include<iostream>
#include<map>
using namespace std;



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

void PrintMap(map<int, int, MyCompare>& m)
{
	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key=" << it->first << " " << "value=" << it->second << endl;
	}
	cout << endl;
}
void test01()
{
	map<int, int,MyCompare>m1;//降序第一种方法
    map<int, int,greater<int>> m2;//降序第二种方法
	m1.insert(make_pair(1, 10));
	m1.insert(make_pair(2, 20));
	m1.insert(make_pair(3, 30));
	m1.insert(make_pair(4, 40));
	m1.insert(make_pair(5, 50));

	PrintMap(m1);
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

  • 利用仿函数可以指定map容器的排序规则
  • 对于自定义数据类型,map必须要指定排序规则,同set容器

3. STL函数对象

3.1 函数对象

3.11 函数对象概念

概念

  • 重载函数调用操作符的类,其对象也称为函数对象
  • 函数对象使用重载()时,行为类似函数调用,也叫仿函数

本质

函数对象(仿函数)是一个类,不是一个函数。

函数对象使用

特点

  • 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
  • 函数对象超出普通函数的概念,函数对象可以有自己的状态
  • 函数对象可以作为参数传递
#include<iostream>
#include<string>
using namespace std;

class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};
//函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
void test01()
{
	MyAdd myadd;
	cout << myadd(10, 10) << endl;
}
//函数对象超出普通函数的概念,函数对象可以有自己的状态
class MyPrint
{
public:
	MyPrint()
	{
		this->count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl; 
		this->count++;
	}

	int count;//内部自己状态
};
void test02()
{
	MyPrint myprint;
	myprint("hello world");
	myprint("hello world");
	myprint("hello world");
	myprint("hello world");
	myprint("hello world");
	myprint("hello world");

	cout << "MyPrint调用次数为:" << myprint.count << endl;


}
//函数对象可以作为参数传递
void doPrint(MyPrint& mp, string test)
{
	mp(test);
}

void test03()
{
	MyPrint myPrint;
	doPrint(myPrint, "hello c++");
}
int main(void)
{
	test01();
	test02();
	test03();
	system("pause");
	return 0;
}

3.2 谓词

3.2.1 谓词概念

概念:

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

一元谓词

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;


class CreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};

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

	//查找容器中,有没有大于5的数字
	//CreaterFive()匿名函数对象
	vector<int>::iterator pos = find_if(v.begin(), v.end(), CreaterFive());

	if (pos == v.end())
	{
		cout << "未找到" << endl;
	}
	else
	{
		cout << "找到了,大于5的数字为:" << *pos << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结
参数中只有一个的谓词,叫做一元谓词

二元谓词

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
class MyCompare
{
public:
	bool operator()(int val1,int val2)
	{
		return val1 > val2;
	}
};

void test01()
{
	vector<int>v;

	v.push_back(10);
	v.push_back(40);
	v.push_back(20);
	v.push_back(30);
	v.push_back(50);
	
	sort(v.begin(), v.end());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	//改变为降序
	sort(v.begin(), v.end(),MyCompare());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

总结

参数只有两个的谓词,称为二元谓词。

3.3 内建函数对象

3.3.1 内建函数对象意义

概念
STL内建了一些函数对象

分类

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

用法

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

3.3.2算数仿函数

功能描述

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

仿函数原型

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V550IQg9-1628485740323)(/images/C++提高编程.assets/image-20210807180847763.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>//内建函数对象头文件
using namespace std;

//megate一元仿函数 取反仿函数
void test01()
{
	negate<int>n;
	cout << n(50) << endl;
}
//plus 二元仿函数 加法
void test02()
{
	//加法仿函数——其他算数仿函数同理
	plus<int>p;//默认认定传的是同种数据类型,同种数据类型尖括号只写一个Int就可以
	cout << p(10, 20) << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

3.3.3 关系仿函数

功能描述
实现关系对比

仿函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AFppV8sw-1628485740324)(/images/C++提高编程.assets/image-20210807181430540.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

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

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

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

	//sort(v.begin(),v.end(), MyCompare());
	/sort(v.begin(),v.end(), greater<int>()); 内建函数对象
	sort(v.begin(),v.end(), greater<int>());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

3.3.4 逻辑仿函数

功能描述
实现逻辑运算

函数原型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ffmdv9xH-1628485740325)(/images/C++提高编程.assets/image-20210807182045371.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

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

	for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	//利用逻辑非 将容器v 搬运到容器v2中,并执行取反操作

	vector<bool>v2;
	v2.resize(v.size());

	transform(v.begin(), v.end(), v2.begin(),logical_not<bool>());//()代表对象的创建

	for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

4. STL常用算法

概述:

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

4.1 常用遍历算法

学习目标
掌握常用的遍历算法

算法简写

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4H8HOfwh-1628485740325)(/images/C++提高编程.assets/image-20210807183624235.png)]

4.1.1 for_each

功能描述
实现遍历容器

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTtUCeyj-1628485740326)(/images/C++提高编程.assets/image-20210807185600354.png)]

#include<iostream>
#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>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	for_each(v.begin(), v.end(),Print01);
	cout << endl;
	for_each(v.begin(), v.end(), Print02());
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

4.1.2 transform

功能描述

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

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DFzRLhy5-1628485740326)(/images/C++提高编程.assets/image-20210808121042420.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;


class TransForm
{
public:
	int operator()(int val)
	{
		return val + 100;
	}
};

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

void test01()
{
	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	vector<int>vTarget;//目标容器
	vTarget.resize(v.size());//目标容器需要提前开辟空间
	transform(v.begin(), v.end(), vTarget.begin(), TransForm());
	for_each(vTarget.begin(), vTarget.end(), MyPrint());
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

 总结
搬运的目标容器必须提前开辟空间,否则无法正常搬运。

4.2 常用查找算法

学习目标
掌握常用的查找算法

算法简介:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KJGxcPlg-1628485740327)(/images/C++提高编程.assets/image-20210808122054017.png)]

4.2.1 find

功能描述
查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ya2YWSg-1628485740327)(/images/C++提高编程.assets/image-20210808122207783.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<string>
using namespace std;

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



//内置数据类型
void test01()
{
	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}

	vector<int>::iterator it = find(v.begin(), v.end(), 5);
	if (it == v.end())
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到" << *it << endl;
	}
}
//自定义数据类型
void test02()
{
	vector<Person>V;
	Person p1("1",11);
	Person p2("2",22);
	Person p3("3",33);
	Person p4("4",44);
	
	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;
	}
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

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

4.2.2 find_if

功能描述

按条件查找元素。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XsAU55X4-1628485740327)(/images/C++提高编程.assets/image-20210808152702486.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<string>
using namespace std;


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);
	}
	vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
	if (it == v.end())
	{
		cout << "没找到" << endl;	
	}
	else
	{
		cout << "找到了" << *it << endl;
	}
}

//自定义数据类型

class Person
{
public:
	Person(string name,int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	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("1",11);
	Person p2("2",22);
	Person p3("3",33);
	Person p4("4",44);

	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(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

4.2.3 adjacent_find

功能描述
查找相邻重复元素。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ILocxasZ-1628485740328)(/images/C++提高编程.assets/image-20210808154226890.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;


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

	vector<int>::iterator it = adjacent_find(v.begin(), v.end());
	if (it == v.end())
	{
		cout << "没找到" << endl;
	}
	else
	{
		cout << "找到相邻重复元素" << *it << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

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

功能描述
查找指定元素是否存在。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cdQt6C6p-1628485740328)(/images/C++提高编程.assets/image-20210808154830292.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;


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

	//这个容器必须是有序的序列,如果是无序的序列,结果未知,查找容器中是否有9这个元素
	bool ret = 	binary_search(v.begin(), v.end(),9);

	if (ret)
	{
		cout << "找到了" << endl;
	}
	else
	{
		cout << "没找到" << endl;
	}
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

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

4.2.5 count

功能描述
统计元素个数。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2emiQaPj-1628485740329)(/images/C++提高编程.assets/image-20210808193158801.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<string>
using namespace std;


//内置数据类型
void test01()
{
	vector<int>v;
	v.push_back(10);
	v.push_back(10);
	v.push_back(40);
	v.push_back(20);
	v.push_back(30);

	int num = count(v.begin(), v.end(), 10);
	cout << num << endl;
}
//自定义数据类型
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	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("s1",11 );
	Person p2("s2",12 );
	Person p3("s3",13 );
	Person p4("s4",14 );
	Person p5("s5",14 );
	
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	
	int num = count(v.begin(), v.end(), p5);

	cout << num << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

总结

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

4.2.6 count_if

功能描述
按条件统计元素个数。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UQF23Aur-1628485740330)(/images/C++提高编程.assets/image-20210808194050713.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

class Greater20
{
public:
	bool operator()(int val)
	{
		return val > 20;
	}
};
//内置数据类型
void test01()
{
	vector<int>v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(40);
	v.push_back(30);
	v.push_back(50);

	int num = count_if(v.begin(), v.end(), Greater20());
	cout << num << endl;
}
//自定义数据类型
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	string m_Name;
	int m_Age;
};


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

};
void test02()
{
	vector<Person>v;
	Person p1("s1",11 );
	Person p2("s2",22 );
	Person p3("s3",33 );
	Person p4("s4",44 );

	v.push_back(p1); 
	v.push_back(p2); 
	v.push_back(p3); 
	v.push_back(p4); 
    //统计 大于20岁人员的个数
	int num = count_if(v.begin(), v.end(),AgeGreater20());
	cout << num << endl;
}
int main(void)
{
	test01();
	test02();
	system("pause");
	return 0;
}

4.3 常用的排序算法

学习目标
掌握常用的排序算法。

算法简介
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-07vcO25z-1628485740331)(/images/C++提高编程.assets/image-20210808195722775.png)]

4.3.1 sort

 功能描述

对容器内元素进行排序。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-21yr2OeJ-1628485740332)(/images/C++提高编程.assets/image-20210808201005005.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;


void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vector<int>v;
	v.push_back(20);
	v.push_back(10);
	v.push_back(60);
	v.push_back(5);
	v.push_back(30);
	v.push_back(2);

	//升
	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(void)
{
	test01();
	system("pause");
	return 0;
}

4.3.2 random_shuffle

功能描述
洗牌 指定范围内的元素随机调整次序。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pwJCIHIS-1628485740332)(/images/C++提高编程.assets/image-20210808201145530.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
#include<ctime>
using namespace std;

void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	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(void)
{
	srand((unsigned int)time(NULL));
	test01();
	system("pause");
	return 0;
}

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

4.3.3 merge

功能描述
两个容器元素合并,并存储到另一个容器中。

函数原型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BJfkBCPw-1628485740333)(/images/C++提高编程.assets/image-20210808201656219.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vector<int>v1;
	vector<int>v2;
	for (int i = 0; i < 5; i++)
	{
		v1.push_back(i);
		v2.push_back(i+5);
	}
	//目标容器
	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(void)
{
	test01();
	system("pause");
	return 0;
}

总结:

merge合并的两个容器必须得是有序序列,合并后得到的容器也是有序的

4.3.4 reverse

功能描述:
将容器内元素进行反转。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TGfeD2Ui-1628485740333)(/images/C++提高编程.assets/image-20210808202328702.png)]

4.4 常用的拷贝和替换算法

学习目标:

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

算法简介:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-atr2dTSy-1628485740333)(/images/C++提高编程.assets/image-20210808203216709.png)]

4.4.1 copy

功能描述:

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

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCanOcpy-1628485740334)(/images/C++提高编程.assets/image-20210808203311990.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

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

	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(void)
{
	test01();
	system("pause");
	return 0;
}

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

4.4.2 replace

功能描述
将容器内指定范围的旧元素修改为新元素。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tWtOq3Zo-1628485740335)(/images/C++提高编程.assets/image-20210808204349016.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vector<int>v;
	v.push_back(20);
	v.push_back(10);
	v.push_back(60);
	v.push_back(50);
	v.push_back(30);
	v.push_back(20);

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

	cout << "替换后" << endl;
	replace(v.begin(), v.end(), 20, 2000);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;


}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

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

4.4.3 replace_if

功能描述
将区间内满足条件的元素,替换成指定元素。

函数原型

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1J06El90-1628485740335)(/images/C++提高编程.assets/image-20210808210008531.png)]

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;

void myPrint(int val)
{
	cout << val << " ";
}
class Great30
{
public:
	bool operator()(int val)
	{
		return val > 30;
	}
};
void test01()
{
	vector<int>v;
	v.push_back(20);
	v.push_back(10);
	v.push_back(60);
	v.push_back(50);
	v.push_back(30);
	v.push_back(20);

	cout << "替换前" << endl;
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	cout << "替换后" << endl;
	replace_if(v.begin(), v.end(),Great30(),3000);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

4.4.4 swap

功能描述:互换两个容器的元素。

函数原型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ab2gvkeB-1628485740336)(/images/C++提高编程.assets/image-20210809092823770.png)]

#include<iostream>
#include<algorithm>
#include<string>
#include<functional>
#include<vector>
using namespace std;
void MyPrint(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(void)
{
	test01();
	system("pause");
	return 0;
}

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

4.5 常用算数生成算法

学习目标
掌握常用的算数生成算法。

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

算法简介:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HYsvcxeq-1628485740336)(/images/C++提高编程.assets/image-20210809093650001.png)]

4.5.1 accumulate

功能描述
计算区间内容器元素累计总和。

函数原型

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TOOfTmRQ-1628485740337)(/images/C++提高编程.assets/image-20210809093837745.png)]

#include<iostream>
#include<vector>
#include<numeric>
using namespace std;
void MyPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vector<int>v;
	for (int i = 0; i <= 100; i++)
	{
		v.push_back(i);
	}
	//参数3是起始累加值
	int total = accumulate(v.begin(), v.end(), 0);
	cout << total << endl;
	
}
int main(void)
{
	test01();
	system("pause");
	return 0;
}

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

4.5.2 fill

功能描述

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

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQ8c0UW6-1628485740338)(/images/C++提高编程.assets/image-20210809094346943.png)]

#include<iostream>
#include<algorithm>
#include<numeric>
#include<vector>
#include<algorithm>

using namespace std;
void MyPrint(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(void)
{
	test01();
	system("pause");
	return 0;
}

4.6 常用集合算法

学习目标

掌握常用的集合算法。

算法简介
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5cHTE3g-1628485740339)(/images/C++提高编程.assets/image-20210809094826986.png)]

4.6.1 set_intersection

功能描述
求两个容器的交集。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxU7irwY-1628485740340)(/images/C++提高编程.assets/image-20210809094922210.png)]

#include<iostream>
#include<algorithm>
#include<string>
#include<functional>
#include<vector>
#include<algorithm>
using namespace std;
void MyPrint(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;
	//最特殊情况,大容器包含小容器,开辟空间 取小的容器的size即可,这样最保守
	vTarget.resize(min(v1.size(),v2.size()));

	//返回迭代器的位置是交集的末尾位置,帮助下面for_each划定区间
	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(void)
{
	test01();
	system("pause");
	return 0;
}

总结:

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

4.6.2 set_union

功能描述
求两个集合的并集。

函数原型

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void MyPrint(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(void)
{
	test01();
	system("pause");
	return 0;
}

总结

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

4.6.3 set_difference

功能描述
求两个集合的差集。

函数原型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0VH2kySj-1628485740342)(/images/C++提高编程.assets/image-20210809103402355.png)]

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

void MyPrint(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;
	//最特殊(保守)情况 两个容器没有交集 取两个容器大的size作为目标容器开辟的空间
	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(void)
{
	test01();
	system("pause");
	return 0;
}

总结:

  • 求差集的两个集合必须得是有序序列。
  • 目标容器开辟空间需要从两个容器取较大值。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值