Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)

  • 前言
  • 三、第三阶段 C++提高编程 介绍C++泛型编程思想,以及STL的基本使用
    • 1.模板
      • 1.1模板的概念
      • 1.2.1函数模板
      • 1.2.2函数模板注意事项
      • 1.2.3函数模板案例
      • 1.2.4普通函数与函数模板的区别
      • 1.2.5普通函数与函数模板的调用规则
      • 1.2.6模板的局限性
      • 1.3.1类模板语法
      • 1.3.2类模板与函数模板的区别
      • 1.3.3类模板中成员函数创建时机
      • 1.3.4类模板对象做函数参数
      • 1.3.5类模板与继承
      • 1.3.6类模板成员函数的类外实现
      • 1.3.7类模板分文件编写
        • Person.h
        • Person.hpp
        • Person.cpp
        • 类模板分文件编写.cpp
      • 1.3.8类模板与友元
      • 1.3.9类模板案例
        • MyArray.hpp
        • 类模板案例.cpp
    • 2.STL初识
      • 2.1-2.4 STL初识
      • 2.5容器算法迭代器初识.jpg
      • 2.5.0容器算法迭代器初识
      • 2.5.1vector存放内置数据类型
      • 2.5.2vector存放自定义数据类型
      • 2.5.3vector容器嵌套容器
    • 3.STL常用容器
      • 3.1string容器
        • 3.1.1string基本概念
        • 3.1.2string构造函数
        • 3.1.3string赋值操作
        • 3.1.4string字符串拼接
        • 3.1.5string查找和替换
        • 3.1.6string字符串比较
        • 3.1.7string字符存取读写
        • 3.1.8string插入和删除
        • 3.1.9string子串
      • 3.2vector容器
        • 3.2.1vector容器.jpg
        • 3.2.1vector基本概念
        • 3.2.2vector构造函数
        • 3.2.3vector赋值操作
        • 3.2.4vector容量和大小
        • 3.2.5vector插入和删除
        • 3.2.6vector数据存取
        • 3.2.7vector互换容器
        • 3.2.8vector预留空间
      • 3.3deque容器
        • 3.3.1(1)deque容器.jpg
        • 3.3.1(2)deque容器.jpg
        • 3.3.1deque容器基本概念
        • 3.3.2deque构造函数
        • 3.3.3deque赋值操作
        • 3.3.4deque大小操作
        • 3.3.5deque插入和删除
        • 3.3.6deque数据存取
        • 3.3.7deque排序
      • 3.4案例-评委打分
      • 3.5stack容器
        • 3.5.1stack容器.jpg
        • 3.5.1stack基本概念
        • 3.5.2stack常用接口
      • 3.6queue容器
        • 3.6.1queue容器.jpg
        • 3.6.1queue基本概念/*
        • 3.6.2queue常用接口
      • 3.7list容器
        • 3.7.1list容器.jpg
        • 3.7.1list基本概念
        • 3.7.2list构造函数
        • 3.7.3list赋值和交换
        • 3.7.4list大小操作
        • 3.7.5list插入和删除
        • 3.7.6list数据存取
        • 3.7.7list反转和排序
        • 3.7.8排序案例
      • 3.8set/multiset容器
        • 3.8.1set基本概念
        • 3.8.2set构造和赋值
        • 3.8.3set大小和交换
        • 3.8.4set插入和删除
        • 3.8.5set查找和统计
        • 3.8.6set和multiset区别
        • 3.8.7pair队组创建
        • 3.8.9(1)set容器-内置类型指定排序规则
        • 3.8.9(2)set容器-自定义数据类型指定排序规则
      • 3.9map/multimap容器
        • 3.9.1map基本概念
        • 3.9.2map构造和赋值
        • 3.9.3map大小和交换
        • 3.9.4map插入和删除
        • 3.9.5map查找和统计
        • 3.9.6map容器排序
      • 3.10案例-员工分组
    • 4.STL-函数对象
      • 4.1函数对象
        • 4.1.1函数对象概念
        • 4.1.2函数对象使用
      • 4.2谓词
        • 4.2.1谓词概念
        • 4.2.2一元谓词
        • 4.2.3二元谓词
      • 4.3内建函数对象
        • 4.3.1内建函数对象意义
        • 4.3.2算数仿函数
        • 4.3.3关系仿函数
        • 4.3.4逻辑仿函数
    • 5.STL-常用算法
      • 5.1常用遍历算法
        • 5.1.1for_each
        • 5.1.2transform
      • 5.2常用查找算法
        • 5.2.1find
        • 5.2.2find_if
        • 5.2.3adjacent_find
        • 5.2.4binary_search
        • 5.2.5count
        • 5.2.6count_if
      • 5.3常用排序算法
        • 5.3.1sort
        • 5.3.2random_shuffle
        • 5.3.3merge
        • 5.3.4reverse
      • 5.4常用拷贝和替换算法
        • 5.4.1copy
        • 5.4.2replace
        • 5.4.3replace_if
        • 5.4.4swap
      • 5.5常用算术生成算法
        • 5.5.1accumulate
        • 5.5.2fill
      • 5.6常用集合算法
        • 5.6.1set_intersection
        • 5.6.2set_union
        • 5.6.3set_difference
    • 6.演讲比赛流程管理系统
    • 7.机房预约系统

前言

黑马的课程里面分为了三大阶段
一、第一阶段 C++基础语法入门 对C++有初步了解,能够有基础编程能力
二、第二阶段 C++核心编程 介绍C++面向对象编程,为大型项目做铺垫
三、第三阶段 C++提高编程 介绍C++泛型编程思想,以及STL的基本使用
※※※我会一个阶段发一个文章,一共发布三个文章来把学习的代码还有自己在代码旁边标注的对于这些代码的理解和心得体会一起分享给大家!!!

该文章的目的:
1.把本人跟着黑马敲的代码都发布在文章内,供大家复制粘贴和参考等等
2.就当作存储代码的一个云空间了,放在电脑里还占内存
3.在学习的时候,对于代码的理解我都在旁边进行了注释,望大家能够快速消化吸收

因为本人还有好多代码是没有深究的,到了后来我记得有一个地方要在类内成员函数后面要加const的这个(2022版本要敲,但是黑马那个2015的就不用),类似的等等,没有特别研究,是看弹幕大佬这么说的我就这么去敲的,所以如果大家能够对这篇文章所有的代码有疑问的话请积极在评论区留言,大家一块讨论。

三、第三阶段 C++提高编程 介绍C++泛型编程思想,以及STL的基本使用

1.模板

1.1模板的概念

/*
模板就是建立通用的模具大大提高复用性
特点:
模板不可以直接使用,它只是一个框架
模板的通用并不是万能的
*/

1.2.1函数模板

#include 
using namespace std;
/*
C++另一种编程思想称为泛型编程,主要利用的技术就是模板
C++提供两种模板机制:函数模板和类模板
*/

/*
函数模板作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表

语法: 
template
函数声明或定义

解释:
template-声明创建模板
typename-表面其后面的符号是一种数据类型,typename也可以用(改成)class代替
T-通用的数据类型,名称可以替换,通常为大写字母

总结:
函数模板利用关键字template
使用函数模板有两种方式:自动类型推导,显式指定类型
模板的目的是为了提高复用性,将类型参数化
*/

//函数模板
//实现两个整型交换的函数
void swapInt(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}
//交换两个浮点型函数
void swapDouble(double& a, double& b)
{
	double temp = a;
	a = b;
	b = temp;
}
//函数模板
template<typename T>//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}
int main1()
{
	cout << "test01:" << endl;
	int a = 10, b = 20;
	//swapInt(a, b);
	//利用函数模板交换
	//两种方式使用函数模板
	//1、自动类型推导
	mySwap(a, b);
	//2、显示指定类型
	mySwap<int>(b, a);
	cout << "a = " << a << endl << "b = " << b << endl;

	double c = 10, d = 20;
	swapDouble(c, d);
	mySwap<double>(c, d);
	cout << "c = " << c << endl << "d = " << d << endl;


	system("pause");
	return 0;
}

1.2.2函数模板注意事项

#include 
using namespace std;
//函数模板注意事项
//1、自动推导类型,必须推导出一致的数据类型T才可以使用
template<class T>//typename可以替换成class
void mySwap1(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}
//2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{
	cout << "func 调用" << endl;
}

int main2()
{
	//1、自动推导类型,必须推导出一致的数据类型T才可以使用
	cout << "test01:" << endl;
	int a = 20, b = 10;
	char c = '123';
	mySwap1(a, b);
	//mySwap(a, c);//推导不出一致的T类型
	
	//2、模板必须要确定出T的数据类型,才可以使用
	cout << "test02:" << endl;
	//func();报错,不知道T的数据类型
	func<int>();

	system("pause");
	return 0;
}

1.2.3函数模板案例

#include 
using namespace std;
/*
案例描述
利用函数模板封装第一个排序的函数,可以对不同数据类型数组进行排序
排序规则从大到小,排序算法为选择排序
分别利用char数组和int数组进行测试
*/

//交换函数模板
template<class T>
void mySwap2(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

//排序算法
template<class T>
void mySort(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i;//认定最大值的下标
		for (int j = i + 1; j < len;j++)
		{
			//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值
			if(arr[max]<arr[j])
			{
				max = j;
			}
		}
		if (max != i)
		{
			//交换max和i的元素
			mySwap2(arr[max], arr[i]);
		}
	}
}

//打印数组模板
template<class T>
void printArray(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

int main3()
{
	cout << "test01: " << endl;
	//测试char数组
	char charArr[] = "badcfe";
	int charlen = sizeof(charArr) / sizeof(char);
	mySort(charArr, charlen);
	printArray(charArr, charlen);

	cout << "test02: " << endl;
	//测试int数组
	int intArr[] = {2,3,6,1,5,2,3,5,3};
	int intlen = sizeof(intArr) / sizeof(int);
	mySort(intArr, intlen);
	printArray(intArr, intlen);

	system("pause");
	return 0;
}

1.2.4普通函数与函数模板的区别

#include 
using namespace std;

//普通函数与函数模板区别
/*
1、普通函数调用可以发生隐式类型转换
2、函数模板用自动类型推导,不可以发生隐式类型转换
3、函数模板用显示指定类型,可以发生隐式类型转换
*/
//建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T
//普通函数
int myAdd01(int a, int b)
{
	return a + b;
}
//函数模板
template<class T>
int myAdd02(T a, T b)
{
	return a + b;
}
int main4()
{
	cout << "test01: " << endl;
	int a = 20, b = 10;
	char c = 'c';
	int ret = myAdd01(a, b);
	cout << "myAdd01(a, b) = " << ret << endl;
	cout << "myAdd01(a, c) = " << myAdd01(a, c) << endl;//把c转换成ASCII码了:a-97,c-99

	cout << "test02: " << endl;
	//cout << "myAdd02(a, c) = " << myAdd02(a, c) << endl;//报错,它不知道也不会把字符型转换成整型
	
	cout << "test03: " << endl;
	cout << "myAdd02(a, c) = " << myAdd02<int>(a, c) << endl;//明确告诉你T是int类型了,字符型能转成int就转了,转不了就报错了
	system("pause");
	return 0;
}

1.2.5普通函数与函数模板的调用规则

#include
using namespace std;
#include 
#include 
/*
功能描述:对deque中的数据的存取操作
函数原型:
at(int idx); //返回索引idx所指的数据
operator[];  //返回索引idx所指的数据
front();     //返回容器中第一个数据元素
back();      //返回容器中最后一个数据元素
*/
void printDeque05(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test22()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque05(d1);

	cout << "d1.at(3) = " << d1.at(3) << endl;
	cout << "d1[5] = " << d1[5] << endl;
	cout << "d1的第一个元素: " << d1.front() << endl;
	cout << "d1的最后的元素: " << d1.back() << endl;
}
int main20()
{
	test22();
	system("pause");
	return 0;
}

1.2.6模板的局限性

#include 
using namespace std;
#include 
//模板局限性
//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
/*
利用具体化的模板,可以解决自定义类型的通用化
学习模板不是为了写模板,而是在STL能够运用系统提供的模板
*/
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};
//对比两个数据是否相等的函数
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//利用具体化Person的版本实现代码(具体化后该函数会被优先调用)
template<> bool myCompare(Person& p1, Person& p2)
{
	if (p1.m_Age == p2.m_Age && p1.m_Name == p2.m_Name)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main6()
{
	cout << "test01: " << endl;
	int a = 10, b = 20;
	bool ret = myCompare(a, b);
	if (ret)
	{
		cout << "相等" << endl;
	}
	else
	{
		cout << "不相等" << endl;
	}

	cout << "test02: " << endl;
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	//编译器不会比较Person的数据类型
	//解决方法:
	//1、运算符重载(麻烦)
	//2、利用具体化的Person的版本来实现代码
	ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "相同" << endl;
	}
	else
	{
		cout << "不相同" << endl;
	}
	system("pause");
	return 0;
}

1.3.1类模板语法

#include 
using namespace std;
#include 
//类模板作用:建立一个通用类,类中的成员数据类型可以不具体指定,用一个虚拟的类型来代表
 
//语法:template
//      类

//解释:
/*
template-声明创建模板
typename-表面其后面的符号是一种数据类型,可以用class代替
T-通用的数据类型,名称可以替换,通常为大写字母
*/

//类模板
template<class NameType,class AgeType>
class Person
{
public:
	Person(NameType name,AgeType age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}

	void showPerson()
	{
		cout << "name: " << this->m_Name << endl;
		cout << "age:  " << this->m_Age << endl;
	}
	NameType m_Name;
	AgeType m_Age;
};
int main7()
{
	cout << "test01: " << endl;
	Person<string,int>p1("孙悟空", 10000);
	p1.showPerson();
	system("pause");
	return 0;
}

1.3.2类模板与函数模板的区别

#include 
using namespace std;
#include 
/*
类模板与函数模板区别主要有两点:
1、类模板没有自动类型推导的使用方式
2、类模板在模板参数列表中可以有默认参数
*/

template<class NameType,class AgeType = int>
//2、class AgeType = int: 类模板在模板参数列表中可以有默认参数
class Person
{
public:
	Person(NameType name, AgeType age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}
	
	void showPerson()
	{
		cout << "name: " << this->m_Name << endl;
		cout << "age: " << this->m_Age << endl;
	}

	NameType m_Name;
	AgeType m_Age;
};
int main8()
{
	//1、类模板没有自动类型推导的使用方式
	cout << "test01: " << endl;
	//Person p("孙悟空", 10000);//无法用自动类型推导
	Person<string, int> p("孙悟空", 10000);
	p.showPerson();

	//2、类模板在模板参数列表中可以有默认参数
	cout << "test02: " << endl;
	Person<string>p1("猪八戒", 1000);
	p1.showPerson();

	system("pause");
	return 0;
}

1.3.3类模板中成员函数创建时机

#include 
using namespace std;

//※类模板中成员函数在调用时才去创建
class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show" << endl;
	}
};

class Person2
{
public:
	void showPerson2()
	{
		cout << "Person2 show" << endl;
	}
};

template<class T>
class MyClass
{
public:
	T obj;
	//类模板中的成员函数
	//※类模板中成员函数在调用时才去创建
	void func1()
	{
		obj.showPerson1();
	}
	void func2()
	{
		obj.showPerson2();
	}
};

int main9()
{
	cout << "test01: " << endl;
	MyClass<Person1>m;
	m.func1();
	//m.func2();//没具体化Person1,只具体化Person2了

	MyClass<Person2>m1;
	m1.func2();
	system("pause");
	return 0;
}

1.3.4类模板对象做函数参数

#include 
using namespace std;
//类模板实例化出的对象,向函数传参的方式
#include 
/*
三种传入方式:
1.指定传入的类型 — 直接显示对象的数据类型
2.参数模板化 — 将对象中的参数变为模板进行传递
3.整个类模板化 — 将这个对象类型 模板化进行传递
*/

template<class T1,class T2>
class Person
{
public:
	Person(T1 name, T2 age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}

	void showPerson()
	{
		cout << "姓名: " << this->m_Name << endl << "年龄: " << this->m_Age << endl;
	}
	T1 m_Name;
	T2 m_Age;
};

//1.指定传入的类型 — 直接显示对象的数据类型
void printPerson1(Person<string,int>&p)
{
	p.showPerson();
}

//2.参数模板化 — 将对象中的参数变为模板进行传递
template<class T1,class T2>
void printPerson2(Person<T1,T2>& p)
{
	p.showPerson();
	cout << "T1的类型为: " << typeid(T1).name() << endl;
	cout << "T1的类型为: " << typeid(T2).name() << endl;
}
//3.整个类模板化 — 将这个对象类型 模板化进行传递
template<class T>
void printPerson3(T &p)
{
	p.showPerson();
	cout << "T的数据类型为: " << typeid(T).name() << endl;
}
int main10()
{
	//1.※指定传入的类型 - 常用的方式
	cout << "test01: " << endl;
	Person<string, int> p("孙悟空", 100);
	printPerson1(p);

	//2.参数模板化
	cout << "test02:" << endl;
	Person<string, int> p2("猪八戒", 10);
	printPerson2(p2);

	//3.整个类模板化
	cout << "test03:" << endl;
	Person<string, int> p3("沙和尚", 1);
	printPerson3(p3);
	system("pause");
	return 0;
}

1.3.5类模板与继承

#include 
using namespace std;

template<class T>
class Base
{
public:
	
	T m;
};

//class Son : public Base//错误,必须要知道父类中的T的数据类型,才能继承给子类
class Son : public Base<int>//实例化个
{
public:

};

//如果想灵活指定父类中T类型,子类也需要变类模板
template<class T1,class T2>
class Son2 :public Base<T2>
{
public:
	Son2()
	{
		cout << "T1的类型为: " << typeid(T1).name() << endl;
		cout << "T2的类型为: " << typeid(T2).name() << endl;
	}
	T1 n;
};
int main11()
{
	cout << "test01: " << endl;
	Son s1;
	

	cout << "test02: " << endl;
	Son2<int, char>s2;

	system("pause");
	return 0;
}

1.3.6类模板成员函数的类外实现

#include 
using namespace std;
#include 


template<class T1,class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	/*{
		this->m_Name = name;
		this->m_Age = age;
	}*/
	void showPerson();
	/*{
		cout << "姓名: " << this->m_Name << endl << "年龄: " << this->m_Age << end;
	}*/

	T1 m_Name; T2 m_Age;
};

//构造函数类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name, T2 age)//Person:: -- 告诉编译器是类模板的类外实现
{
	this->m_Name = name;
	this->m_Age = age;
}
//成员函数类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名: " << this->m_Name << endl << "年龄: " << this->m_Age << endl;
}
int main12()
{
	cout << "test01" << endl;
	Person<string, int> p("Tom", 12);
	p.showPerson();

	system("pause");
	return 0;
}

1.3.7类模板分文件编写

Person.h
#pragma once
#include 
using namespace std;
#include 

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 m_Name;
	T2 m_Age;
};
Person.hpp
#pragma once
#include 
using namespace std;
#include 

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();
	T1 m_Name;
	T2 m_Age;
};


template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名: " << this->m_Name << endl << "年龄" << this->m_Age << endl;
}
Person.cpp
#include "Person.h"

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名: " << this->m_Name << endl << "年龄" << this->m_Age << endl;
}
类模板分文件编写.cpp
#include 
using namespace std;

//解决方式1:直接包含cpp.源文件
#include "Person.cpp"

//主流的解决方法
//解决方式2:将.h和.cpp中的内容写到一起,后缀名改为.hpp文件
#include "Person.hpp"//一看就知道头文件这个是个类模板,.hpp的后缀是约定俗成的
/*
问题:类模板中成员函数创建时机实在调用阶段,导致分文件编写时链接不到

解决:
解决方式1:直接包含cpp.源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
*/


int main13()
{
	
	cout << "test01: " << endl;
	Person<string, int>p("宝贝", 1);
	p.showPerson();
	
	system("pause");
	return 0;
}

1.3.8类模板与友元

#include 
using namespace std;
#include 

//由于类外全局函数的实现涉及了Person类
//因此要先声明Person,让编译器知道有Person的存在
//并且Person的存在要早于类外实现的全局函数printPerson2
template<class T1, class T2>//同时要声明这个Person类是模板类
class Person;

//2、全局函数 类外实现
//要先声明该函数,让编译器先知道函数printPerson2的存在
template<class T1, class T2>
void printPerson2(Person<T1, T2>p)//函数模板的实现
{
	cout << "类外实现---姓名: " << p.m_Name << endl << "年龄: " << p.m_Age << endl;
}


template<class T1, class T2>
class Person
{
	//1、※全局函数 类内实现 ---推荐使用
	//通过全局函数 打印Person信息
	friend void printPerson1(Person<T1, T2>p)
	{
		cout << "类内实现---姓名: " << p.m_Name << endl << "年龄: " << p.m_Age << endl;
	}

	//2、全局函数 类外实现
	//加一个空模板的参数列表"<>"
	//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson2<>(Person<T1, T2>p);//普通函数的声明

public:
	Person(T1 name,T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	
	private:
	T1 m_Name;
	T2 m_Age;
};




int main14()
{
	//1、全局函数 类内实现
	cout << "test01: " << endl;
	Person<string, int>p1("tom",21);
	printPerson1(p1);

	//2、全局函数 类外实现
	cout << "test02: " << endl;
	Person<string, int>p2("tim", 23);
	printPerson2(p2);

	system("pause");
	return 0;
}

1.3.9类模板案例

MyArray.hpp
//自己的通用的数组类
#pragma once
#include 
using namespace std;

template<class T>
class MyArray
{

public:
	//有参构造 参数 容量
	MyArray(int capacity)
	{
		//cout << "MyArray的有参构造调用: " << endl;
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];
	}

	//拷贝构造函数
	MyArray(const MyArray& arr)
	{
		//cout << "MyArray的拷贝构造调用: " << endl;
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		//this->pAddress = arr.pAddress;//复制了一个指针指向相同的地址浅拷贝的问题会导致堆区重复释放

		//深拷贝
		this->pAddress = new T[arr.m_Capacity];
		//将arr中的数据都拷贝过来
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	//operator= 防止浅拷贝问题
	MyArray& operator=(const MyArray&arr)
	{
		//cout << "MyArray的operator = 调用: " << endl;
		//先判断原来堆区是否有数据,如果有先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}

		//深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];
		for (int i = 0; i < m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}

		return*this;

	}

	//尾插法
	void Insert_Behind(const T& val)
	{
		//判断容量是否等于数组大小
		if (this->m_Capacity == this->m_Size)
		{
			cout << "数组容量已满" << endl;
			return;
		}
		this->pAddress[this->m_Size] = val;//在数组末尾插入数据
		this->m_Size++;//更新数组大小
	}

	//尾删法
	void Delete_Behind()
	{
		//让用户访问不到最后一个元素,即为尾删
		if (this->m_Size == 0)
		{
			cout << "不含元素" << endl;
			return;
		}
		this->m_Size--;//逻辑上的尾删
	}

	//通过下标方式访问数组中的元素 arr[0]=100,如果要作为左值的话要用到引用&
	T& operator[](int index)
	{
		return this->pAddress[index];
	}

	//返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}

	//返回数组大小
	int getSize()
	{
		return this->m_Size;
	}
	//析构函数
	~MyArray()
	{
		//cout << "MyArray的析构函数调用: " << endl;
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}
private:
	T* pAddress;//指针指向堆区开辟的真实数组
	int m_Capacity;//数组容量
	int m_Size;//数组大小
};
类模板案例.cpp
#include 
using namespace std;

/*
实现一个通用的数组类
要求:
可以对内置数据类型以及自定义数据类型的数据进行存储
将数组中的数据存储到堆区
构造函数中可以传入数组的容量
提供对应的拷贝构造函数以及operator=防止浅拷贝问题
提供尾插法和尾删法对数组中的数据进行增加和删除
可以通过下标的方式访问数组中的元素
可以获取数组中当前元素个数和数组的容量
*/
#include "MyArray.hpp"
#include 

void printIntArray(MyArray<int>&arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << endl;
	}
}
void test01()
{
	MyArray<int>arr1(5);
	for (int i = 0; i < 5; i++)
	{
		//利用尾插法向数组中插入数据
		arr1.Insert_Behind(i);
	}
	cout << "arr1的打印输出为: " << endl;
	printIntArray(arr1);
	cout << "arr1的容量为: " << arr1.getCapacity() << endl;
	cout << "arr1的大小为: " << arr1.getSize() << endl;
	

	MyArray<int>arr2(arr1);
	cout << "arr2的打印输出为: " << endl;
	printIntArray(arr2);
	//尾删
	arr2.Delete_Behind();
	cout << "arr2尾删后: " << endl;
	cout << "arr2的容量为: " << arr2.getCapacity() << endl;
	cout << "arr2的大小为: " << arr2.getSize() << endl;

}

//自定义数据类型
class Person
{
public:
	string m_Name;
	int m_Age;

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

void printPersonArray(MyArray<Person>& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名: " << arr[i].m_Name << "  年龄: " << arr[i].m_Age << endl;
	}
}
void test02()
{
	MyArray<Person>arr(10);
	Person p1("里维", 18);
	Person p2("艾伦", 18);
	Person p3("三笠", 18);
	Person p4("阿尔敏", 18);
	Person p5("艾尔文", 18);
	Person p6("莎夏", 18);
	Person p7("韩吉", 18);
	Person p8("希斯特里亚雷斯", 18);
	Person p9("让", 18);
	Person p10("尤米尔", 18);
	//将数据插入到数组中
	arr.Insert_Behind(p1); arr.Insert_Behind(p2); arr.Insert_Behind(p3); 
	arr.Insert_Behind(p4); arr.Insert_Behind(p5); arr.Insert_Behind(p6);
	arr.Insert_Behind(p7);
	arr.Insert_Behind(p8); arr.Insert_Behind(p9); arr.Insert_Behind(p10);
	//打印数组
	printPersonArray(arr);
	//输入容量和大小
	cout << "输入容量: " << arr.getCapacity() << endl
		<< "  输入大小:" << arr.getSize() << endl;
}
int main15()
{
	test01();
	test02();
	system("pause");
	return 0;
}

2.STL初识

2.1-2.4 STL初识

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

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

2.3 STL六大组件
STL分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
1.容器:各种数据结构,如vector,list,deque,set,map等,用来存放数据
2.算法:各种常用的算法,如sort,find,copy,for_each等
3.迭代器:扮演了容器与算法之间的胶合剂
4.仿函数:行为类似函数,可作为算法的某种策略
5.适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
6.空间适配器:负责空间的配置与管理

2.4 STL中容器、算法、迭代器
容器:置物之所也
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组、链表、树、栈、队列、集合、映射表等
这些容器分为序列式容器和关联式容器两种:
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

算法:问题之解法也
有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(algorithms)
算法分为:质变算法和非质变算法。
质变算法:是指运算过程中会更改区间内的元素的内容,例如:拷贝,替换,删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找,计数,遍历,寻找极值等等

迭代器:容器和算法之间的粘合剂
提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
常用的容器中迭代器种类为双向迭代器和随机访问迭代器
*/

2.5容器算法迭代器初识.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第1张图片

2.5.0容器算法迭代器初识

/*
了解STL中容器、算法、迭代器概念后,我们利用代码感受STL的魅力
STL中最常用的容器为vector,可以理解为数组,下面我们将学习如何向这个容器中插入数据,并遍历这个容器
*/

2.5.1vector存放内置数据类型

#include 
using namespace std;
/*
容器:vector
算法:for_each
迭代器:vector::iterator
*/
#include 
#include //标准算法头文件
void myPrint(int val)
{
	cout << val << endl;
}
void test01()
{
	//创建一个vector容器,可以视为数组
	vector<int>v;
	//向容器中插入数据,调用内在函数push_back()
	v.push_back(10); v.push_back(30); v.push_back(20); 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 )
	for_each(v.begin(),v.end(),myPrint);

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

2.5.2vector存放自定义数据类型

#include 
using namespace std;
#include 

#include 
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;
};

//存放自定义数据类型
void test02()
{
	vector<Person>v;
	Person p1("aa", 10); Person p2("bb", 30); Person p3("cc", 20);
	Person p4("dd", 11); Person p5("ca", 10); Person p6("ac", 10);
	//向容器中添加数组
	v.push_back(p1); v.push_back(p2); v.push_back(p3);
	v.push_back(p4); v.push_back(p5); v.push_back(p6);
	//遍历容器中的数据
	//1.容器(指针)解引用后用"."的方式拿出来我们的数据
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << (*it).m_Name << " 年龄: " << (*it).m_Age << endl;
	}

	cout << endl;

	//2.容器(指针)直接用"->"来拿出我们的数据
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
	}
}

//存放自定义数据类型的指针
void test03()
{
	vector<Person*>v;
	Person p1("aa", 10); Person p2("bb", 30); Person p3("cc", 20);
	Person p4("dd", 11); Person p5("ca", 10); Person p6("ac", 10);
	//向容器中添加数组
	//由于是指针,这里要传的是地址,要用"&"
	v.push_back(&p1); v.push_back(&p2); v.push_back(&p3);
	v.push_back(&p4); v.push_back(&p5); v.push_back(&p6);

	//遍历容器中的数据
	//1.容器(指针)解引用后,用"."的方式拿出来我们的数据
	//先解引用it指针,来提取出Person指针,再解引用Person指针来提取出我们要的数据
	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << ( *(*it)).m_Name << " 年龄: " << (*(*it)).m_Age << endl;
	}

	cout << endl;

	//2.容器(指针)直接用"->"来拿出我们的数据
	//先解引用it指针,来提取出Person指针,再通过Person指针来进行"->"提取出数据
	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << (*it)->m_Name << " 年龄: " << (*it)->m_Age << endl;
	}
}
int main2()
{
	test02();
	cout << endl;
	test03();

	system("pause");
	return 0;
}

2.5.3vector容器嵌套容器

#include 
using namespace std;
#include 

#include

void test04()
{
	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++)
	{
		//(*it)---容器vector
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			cout << (*vit) << " ";
		}
		cout << endl;
	}
}
int main3()
{
	test04();
	system("pause");
	return 0;
}

3.STL常用容器

3.1string容器

3.1.1string基本概念

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

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

特点:
string类内部封装了很多成员方式
例如:查找find,拷贝copy,删除delete,替换replace,插入insert
string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
*/

3.1.2string构造函数
#include
using namespace std;
#include 
#include 
#include 
/*
构造函数模型:
string();                        //创建一个空的字符串 例如:string str;
string(const char* s);           //使用字符串s初始化
string(const string &str);       //使用一个string对象初始化另一个string对象
string(int n,char c);            //使用n个字符串c初始化
*/
//要会灵活使用
void test01()
{
	//string();                        //创建一个空的字符串 例如:string str;
	string s1;//默认构造
	//string(const char* s);           //使用字符串s初始化
	const char* str = "hello world";
	string s2(str);
	cout << "s2 = " << s2 << endl;
	//string(const string &str);       //使用一个string对象初始化另一个string对象
	string s3(s2);
	cout << "s3 = " << s3 << endl;
	//string(int n,char c);            //使用n个字符串c初始化
	string s4(10, 'a');
	cout << "s4 = " << s4 << endl;
}
int main1()
{
	test01();
	system("pause");
	return 0;
}
3.1.3string赋值操作
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:
给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赋给当前字符串
stirng& assign(int n,char c);         //用n个字符c赋给当前字符串
*/

void test02()
{
	//string& operator=(const char* s);     //char*类型字符串 赋值给当前的字符串
	string str1;
	str1 = "hello world";
	cout << "str1 = " << str1 << endl;
	//string& operator=(const string &s);   //把字符串s赋给当前的字符串
	string str2;
	str2 = str1;
	cout << "str2 = " << str2 << endl;
	//string& operator=(char c);            //字符赋给当前的字符串
	string str3;
	str3 = 'a';
	cout << "str3 = " << str3 << endl;
	//string& assign(const char* s);        //把字符串s赋给当前的字符串
	string str4;
	str4.assign("hello C++");
	cout << "str4 = " << str4 << endl;
	//string& assign(const char* s,int n);  //把字符串s的前n个字符赋给当前的字符串
	string str5;
	str5.assign("hello C++", 7);
	cout << "str5 = " << str5 << endl;
	//string& assign(const string &s);      //把字符串s赋给当前字符串
	string str6;
	str6.assign(str5);
	cout << "str6 = " << str6 << endl;
	//stirng& assign(int n,char c);         //用n个字符c赋给当前字符串
	string str7;
	str7.assign(3, 'b');
	cout << "str7 = " << str7 << endl;
}
int main2()
{
	test02();
	system("pause");
	return 0;
}
3.1.4string字符串拼接
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:实现在字符串末尾拼接字符串

函数原型:
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个字符连接到字符串结尾
*/
void test03()
{
	//string& operator=(const char* str);          //重载+=操作符
	string str1 = "我";
	str1 += "爱玩游戏";
	cout << "str1 = " << str1 << endl;
	//string& operator=(const char c);             //重载+=操作符
	str1 += ':';
	cout << "str1 = " << str1 << endl;
	//string& operator=(const string& str);        //重载+=操作符
	string str2 = "LOL DNF";
	str1 += str2;
	cout << "str1 = " << str1 << endl;
	//string& append(const char* s);               //把字符串s连接到当前字符串结尾
	string str3 = "I";
	str3.append(" love ");
	cout << "str3 = " << str3 << endl;
	//string& append(const char* s,int n);         //把字符串s的前n个字符连接到当前字符串结尾
	str3.append("game abdce", 6);
	cout << "str3 = " << str3 << endl;
	//string& append(const string &s);             //同operator +=(const string &str)
	str3.append(str2);
	cout << "str3 = " << str3 << endl;
	//string& append(const string &s,int pos,int n)//字符串s中从pos开始的n个字符连接到字符串结尾
	str3.append(str2,3,3);
	cout << "str3 = " << str3 << endl;
}
int main3()
{
	test03();
	system("pause");
	return 0;
}
3.1.5string查找和替换
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:
查找:查找指定字符串是否存在
替换:在指定的位置替换字符串

函数原型:
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第一次出现位置

int rfind(const string &str, int pos = npos)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(const char c,int pos = 0)const;          //查找字符c最后一次出现位置

string& replace(int pos,int n,const string &str);  //替换从pos开始n个字符为字符串str
string& replace(int pos,int n,const char* s);      //替换从pos开始n个字符为字符串s
*/

//查找
void test04()
{
	
	//find
	string str1 = "abcdefgde";
	int pos1 = str1.find("de");
	if (pos1 == -1)
	{
		cout << "未找到字符串" << endl;
	}
	else
	{
		cout << "找到字符串,pos1 = " << pos1 << endl;
	}
	
	//rfind和find的区别
	//find是从左往右查找,rfind是从右往左查
	int pos2 = str1.rfind("de");
	cout << "pos2 = " << pos2 << endl;
	
}
//替换
void test05()
{

	string str1 = "abcdefg";
	//从1号位置起,3个字符替换为"1111"
	str1.replace(1, 3, "1111");
	cout << "str1 = " << str1 << endl;

}
int main4()
{
	test04();
	test05();
	system("pause");
	return 0;
}
3.1.6string字符串比较
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:
字符串之间的比较

比较方式:
字符串比较是按字符的ASCII码进行对比
= 返回0  ;  > 返回1   ; < 返回-1

函数原型:
int compare(const string &s)const;//与字符串s比较
int compare(const char* s)const;  //与字符串s比较
*/
void test06()
{
	string str1 = "hello";
	string str2 = "hello";
	if (str1.compare(str2) == 0)
	{
		cout << "str1 = str2" << endl;
	}
	else if(str1.compare (str2)==1)
	{
		cout << "str1 > str2" << endl;
	}
	else
	{
		cout << "str1 < str2" << endl;
	}
}
int main5()
{
	test06();
	system("pause");
	return 0;
}
3.1.7string字符存取读写
#include
using namespace std;
#include 
#include 
#include 
/*
string中单个字符存取方式有两种:
char& operator[](int n);
char& at(int n);
*/
void test07()
{
	string str = "hello";
	cout << "str = " << str << endl;

	//通过中括号来访问单个字符
	for (int i = 0; i < str.size(); i++)
	{
		cout << str[i] << " ";
	}
	cout << endl;
	//通过at来访问单个字符
	for (int i = 0; i < str.size(); i++)
	{
		cout << str.at(i) << " ";
	}
	cout << endl;

	//修改单个字符
	str[0] = 'm';
	cout << "str = " << str << endl;

	str.at(4) = 'y';
	cout << "str = " << str << endl;
}

int main6()
{
	test07();

	system("pause");
	return 0;
}
3.1.8string插入和删除
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:对string字符串进行插入和删除字符操作

函数原型:
string& insert(int pos,const char* s);     //插入字符串
string& insert(int pos,const string& str); //插入字符串
string& insert(int pos,int n,char c);      //在指定位置插入n个字符
string& erase(int pos,int n=npos);         //删除从pos开始的n个字符
*/
void test08()
{
	string str = "hello";

	str.insert(1, "111");
	cout << "str = " << str << endl;

	str.insert(5, 5, 'b');
	cout << "str = " << str << endl;

	str.erase(1, 1);
	cout << "str = " << str << endl;

}
int main7()
{
	test08();
	system("pause");
	return 0;
}
3.1.9string子串
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:从字符串中获取想要的字串
函数原型:string substr(int pos = 0,int n = npos)const; 
//返回由pos开始的n个字符组成的字符串
/*/
void test09()
{
	string str = "abcdef";
	string ret = str.substr(1, 3);
	cout << "ret = " << ret << endl;
}
//实用操作
void test10()
{
	string email = "[email protected]";
	//从邮件地址中 获取 用户名信息
	int pos = email.find('@');
	string ret = email.substr(0, pos);
	//一样的:pos = email.find("@");
	cout << "姓名为: " << ret << endl;

	email = "[email protected]";
	pos = email.find("@");
	ret = email.substr(0, pos);
	cout << "姓名为: " << ret << endl;
}
int main8()
{
	test09();
	test10();
	system("pause");
	return 0;
}

3.2vector容器

3.2.1vector容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第2张图片

3.2.1vector基本概念

/*
功能:vector数据结构和数组非常相似,也成为单端数组

vector与普通数组区别:不同之处在于数组是静态空间,而vector是动态扩展

动态扩展:并不是在原空间的后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间

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

3.2.2vector构造函数
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:
创建vector容器

函数原型:
vector v;              //采用模板实现类实现,默认构造函数
vector(v.begin(),v.end());//将v[begin(),end())区间中的元素拷贝给本身
vector(n,elem);           //构造函数将n个elem拷贝给本身
vector(const vector& vec);//拷贝构造函数
*/
void printVector01(vector<int>&v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test11()
{
	vector<int>v1;//默认构造 无参构造
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector01(v1);

	//通过区间方式进行构造
	vector<int>v2(v1.begin(), v1.end());
	printVector01(v2);

	//n个element方式构造
	vector<int>v3(10, 100);
	printVector01(v3);

	//拷贝构造
	vector<int>v4(v3);
	printVector01(v4);
}
int main9()
{
	test11();
	
	system("pause");
	return 0;
}
3.2.3vector赋值操作
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:给vector容器进行赋值
函数原型:
vector& operator=(const vector& vec); //重载等号操作符
assign(beg,end);                      //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);                       //将n个elem拷贝赋值给本身
*/
void printVector02(vector<int>&v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test12()
{
	vector<int>v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector02(v1);

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

	//assign
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());//区间是前闭后开
	printVector02(v3);

	//n个elem方式赋值
	vector<int>v4;
	v4.assign(10, 100);
	printVector02(v4);
}
int main10()
{
	test12();
	system("pause");
	return 0;
}
3.2.4vector容量和大小
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:对vector容器的容量和大小操作

函数原型:
empty();              //判断容器是否为空
capacity();           //容器的容量
size();               //返回容器中元素的个数
resize(int num);      //重新指定容器的长度为num,若容器变长,则以默认值填充新位置;若容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置;若容器变短,则末尾超出容器长度的元素被删除
*/
void printVector03(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test13()
{
	vector<int>v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector03(v1);

	//判断容器是否为空  容器为空的话返回真(1)
	if (v1.empty())
	{
		cout << "v1为空" << endl;
	}
	else
	{
		cout << "v1不为空" << endl;
		cout << "v1的容量为: " << v1.capacity() << endl;
		cout << "v1的大小为: " << v1.size() << endl;
	}

	//重新指定大小
	v1.resize(15);
	printVector03(v1);//如果重新指定的比原来长了,默认用0填充新的位置
	//指定某数来填充
	v1.resize(17, 100);
	printVector03(v1);
	//变短
	v1.resize(10);
	printVector03(v1);
}
int main11()
{
	test13();
	system("pause");
	return 0;
}
3.2.5vector插入和删除
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:对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(cosnt_iterator start,const_iterator end); //删除迭代器从start到end之间的元素
clear();                                        //删除容器中所有元素
*/
void printVector04(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test14()
{
	vector<int>v1;
	//尾插
	v1.push_back(10); v1.push_back(20); v1.push_back(30); v1.push_back(40); v1.push_back(50);
	printVector04(v1);//遍历容器
	//尾删
	v1.pop_back();
	printVector04(v1);
	//插入 第一个参数是迭代器
	v1.insert(v1.begin(), 100);
	printVector04(v1);
	
	v1.insert(v1.begin(), 2, 100);
	printVector04(v1);
	//删除
	v1.erase(v1.begin());
	printVector04(v1);
	//清空
	//v1.erase(v1.begin(), v1.end());
	v1.clear();
	printVector04(v1);
}
int main12()
{
	test14();
	system("pause");
	return 0;
}
3.2.6vector数据存取
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:对vector中的数据的存取操作
函数原型:
at(int idx); //返回索引idx所指的数据
operator[];  //返回索引idx所指的数据
front();     //返回容器中第一个数据元素
back();      //返回容器中最后一个数据元素
*/
void printVector05(vector<int>& v)
{
	//利用中括号的方式来访问数组中的元素
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;
	//利用at方式访问元素
	for (int i = 0; i < v.size(); i++)
	{
		cout << v.at(i) << " ";
	}
	cout << endl;
	//获取第一个元素
	cout << "第一个元素: " << v.front() << endl;
	//获取最后的元素
	cout << "最后的元素: " << v.back() << endl;
}
void test15()
{
	vector<int>v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}

	printVector05(v1);
}
int main13()
{
	test15();
	system("pause");
	return 0;
}
3.2.7vector互换容器
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:实现两个容器内元素进行互换
函数原型:
swap(vec); //将vec与本身的元素互换,本质上是指针(的指向)的交换
*/
void printVector06(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test16()
{
	vector<int>v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	cout << "交换前: " << endl;
	printVector06(v1);
	
	vector<int>v2;
	for (int i = 10; i > 0; i--)
	{
		v2.push_back(i);
	}
	printVector06(v2);
	//基本使用
	cout << "交换后: " << endl;
	v1.swap(v2);
	printVector06(v1);
	printVector06(v2);

	//实际用途
	//巧用swap可以收缩内存空间
	vector<int>v3;
	for (int i = 0; i < 100000; i++)
	{
		v3.push_back(i);
	}
	cout << "v3的容量为: " << v3.capacity() << endl;
	cout << "v3的大小为: " << v3.size() << endl;
	
	v3.resize(3);//重新指定大小
	cout << "v3的容量为: " << v3.capacity() << endl;
	cout << "v3的大小为: " << v3.size() << endl;

	vector<int>(v3).swap(v3);
	//vector(v3)为匿名对象(调用了拷贝构造函数来匿名新的对象),初始化的时候是按照当前v3所使用的元素个数(所占的大小)来初始化该匿名对象的容量和大小
	//当前行执行完后,系统会回收匿名对象
	cout << "v3的容量为: " << v3.capacity() << endl;
	cout << "v3的大小为: " << v3.size() << endl;
}
int main14()
{
	test16();
	system("pause");
	return 0;
}
3.2.8vector预留空间
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:减少vector在动态扩展容量时的扩展次数
          如果数据量较大,可以一开始利用reserve预留空间
函数原型:
reserve(int len);//容器预留len个元素长度,预留位置不初始化,元素不可访问
*/
void printVector07(vector<int>& v)
{
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test17()
{
	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 = " << num << endl;

	//利用reserve预留空间
	v1.reserve(100000);
	num = 0;
	for (int i = 0; i < 100000; i++)
	{
		v1.push_back(i);

		if (p != &v1[0])
		{
			p = &v1[0];
			num++;
		}
	}
	cout << "开辟次数num = " << num << endl;
	//printVector07(v1);
}
int main15()
{
	test17();
	system("pause");
	return 0;
}

3.3deque容器

3.3.1(1)deque容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第3张图片

3.3.1(2)deque容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第4张图片

3.3.1deque容器基本概念

/*
功能:双端数组,可以对头端进行插入删除操作

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

deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

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

3.3.2deque构造函数
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:deque容器构造
函数原型:
dequedeqT;           //默认构造形式
deque(beg,end);         //构造函数将[beg,end)区间中的元素拷贝给本身
deque(n,elem);          //构造函数将n个elem拷贝给本身
deque(const deque& deq);//拷贝构造函数

deque容器和vector容器构造几乎一样,灵活使用
*/
void printDeque01(const deque<int>& d)//只读的容器需要只读的迭代器
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)//只读的迭代器 -- deque::const_iterator it
	{
		//*it=100;//容器中的数据不可以修改了
		cout << *it << " ";
	}
	cout << endl;
}
void test18()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque01(d1);

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

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

	deque<int>d4(d3);
	printDeque01(d4);
}
int main16()
{
	test18();
	system("pause");
	return 0;
}
3.3.3deque赋值操作
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:给deque容器进行赋值
函数原型:
deque& operator=(const deque &deq); //重载等号操作符
assign(beg,end);                    //将[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);                     //将n个elem拷贝赋值给本身
*/
void printDeque02(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test19()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	} 
	printDeque02(d1);

	//operator= 赋值
	deque<int>d2;
	d2 = d1;
	printDeque02(d2);
	//assign赋值
	deque<int>d3;
	d3.assign(d2.begin(), d2.end());
	printDeque02(d3);
	
	deque<int>d4;
	d4.assign(10, 100);
	printDeque02(d4);
}
int main17()
{
	test19();
	system("pause");
	return 0;
}
3.3.4deque大小操作
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:对deque容器的大小进行操作
函数原型:
deque.empty();          //判断容器是否为空
deque.size();           //返回容器中元素的个数
deque.resize(num);      //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
                        //如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num,elem); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
                        //如果容器变短,则末尾超出容器长度的元素被删除
*/
void printDeque03(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test20()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque03(d1);

	if (d1.empty())
	{
		cout << "容器为空" << endl;
	}
	else
	{
		cout << "容器不为空" << endl;
		cout << "d1的大小为: " << d1.size() << endl;
	}

	d1.resize(100,1); printDeque03(d1);
	d1.resize(3); printDeque03(d1);
}
int main18()
{
	test20();
	system("pause");
	return 0;
}
3.3.5deque插入和删除
#include
using namespace std;
#include 
#include 
#include 
/*
功能描述:向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位置的数据,返回下一个数据的位置
*/
void printDeque04(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test21()
{
	deque<int>d1;
	//头插
	d1.push_front(20); d1.push_front(10);
	//尾插
	d1.push_back(30); d1.push_back(40);
	printDeque04(d1);
	//尾删
	d1.pop_back();
	//头删
	d1.pop_front();
	printDeque04(d1);
	//insert插入
	d1.insert(d1.begin(), 1000);
	printDeque04(d1);
	d1.insert(d1.end(), 7, 10);
	printDeque04(d1);

	d1.insert(d1.begin(),d1.begin(), d1.end());
	printDeque04(d1);

	d1.clear();
	printDeque04(d1);

	deque<int>d2;
	for (int i = 0; i < 10; i++)
	{
		d2.push_back(i);
	}
	d2.erase(d2.begin());
	printDeque04(d2);
	deque<int>::iterator it = d2.end();
	it--;
	d2.erase(it);
	printDeque04(d2);
	d2.erase(d2.begin(), d2.end());
	printDeque04(d2);

}
int main19()
{
	test21();
	system("pause");
	return 0;
}
3.3.6deque数据存取
#include
using namespace std;
#include 
#include 
/*
功能描述:对deque中的数据的存取操作
函数原型:
at(int idx); //返回索引idx所指的数据
operator[];  //返回索引idx所指的数据
front();     //返回容器中第一个数据元素
back();      //返回容器中最后一个数据元素
*/
void printDeque05(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test22()
{
	deque<int>d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque05(d1);

	cout << "d1.at(3) = " << d1.at(3) << endl;
	cout << "d1[5] = " << d1[5] << endl;
	cout << "d1的第一个元素: " << d1.front() << endl;
	cout << "d1的最后的元素: " << d1.back() << endl;
}
int main20()
{
	test22();
	system("pause");
	return 0;
}
3.3.7deque排序
#include
using namespace std;
#include 
#include 
#include //标准算法头文件
/*
功能描述:利用算法实现对deque容器进行排序
算法:
sort(iterator beg,iterator end); //对beg和end区间内元素进行排序

对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序,即vector容器也可以
*/
void printDeque06(const deque<int>& d)
{
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test23()
{
	deque<int>d1;
	for (int i = 10; i > 0; i--)
	{
		d1.push_back(i);
	}
	printDeque06(d1);
	cout << "排序后的结果: " << endl;
	sort(d1.begin(), d1.end());
	printDeque06(d1);

}
int main21()
{
	test23();
	system("pause");
	return 0;
}

3.4案例-评委打分

/*
案例描述:
有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。

实现步骤:
1.创建五名选手,放到vector中
2.遍历vector容器,取出来每一个选手,执行for循环,可以把10个评委打分存到deque容器中
3.sort算法对deque容器中分数排序,去除最高和最低分
4.deque容器遍历一遍,累加总分
5.获取平均分
*/

#include 
using namespace std;
#include 
#include 
#include 
#include 
#include //随机数种子所需的头文件

class Person
{
public:
	Person(string name, int score)
	{
		this->m_Name = name;
		this->m_Score = score;
	}
	string m_Name; //姓名
	int m_Score;   //平均分
};
void createPerson(vector<Person>& v)
{
	string nameSeed = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
		string name = "选手";
		name += nameSeed[i];
		int score = 0;
		Person p(name, score);
		//将创建的Person对象放入到容器中
		v.push_back(p);
	}
}
void setScore(vector<Person>& v)
{
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		//将评委的分数放入到deque容器中
		deque<int>d;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 41 + 60;//60~100
			d.push_back(score);
		}

		cout << it->m_Name << "的打分:";
		for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			cout << *dit << " " ;
		}
		cout << endl;

		//先排序
		sort(d.begin(), d.end());
		//去除最高分和最低分
		d.pop_back();
		d.pop_front();
		//取平均分
		int sum = 0;
		for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			sum += *dit;//累加每个评委的分数
		}
		int avg = sum / d.size();

		//将平均分赋值给选手身上
		it->m_Score = avg;
	}
}
void showScore(vector<Person>& v)
{
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << it->m_Name << "平均分为: " << it->m_Score << endl;
	}
}
int main22()
{
	//随机数种子
	srand((unsigned int)time(NULL));
	//1、创建五名选手
	vector<Person>v;//存放选手容器
	createPerson(v);

	//测试
	//for (vector::iterator it = v.begin(); it != v.end(); it++)
	//{
	//	cout << "姓名: " << (*it).m_Name << "  分数: " << (*it).m_Score << endl;
	//}
	
	//2、给五名选手打分
	setScore(v);
	//3、显示最后得分
	showScore(v);

	system("pause");
	return 0;
}

3.5stack容器

3.5.1stack容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第5张图片

3.5.1stack基本概念

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

栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为
栈中进入数据称为–入栈 push
栈中弹出数据称为–出栈 pop

栈可以判断容器是否为空吗? 可以 empty()
栈可以返回元素个数吗? 可以 size()
*/

3.5.2stack常用接口
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:栈容器常用的对外接口

构造函数:
stack stk;                       //stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk);            //拷贝构造函数
赋值操作:
stack& operator=(const stack& stk); //重载等号操作符
数据存取:
push(elem);                         //向栈顶添加元素
pop();                              //从栈顶移除第一个元素
top();                              //返回栈顶元素
大小操作:
empty();                            //判断堆栈是否为空
size();                             //返回栈的大小
*/
void test24()
{
	stack<int>s;
	//入栈
	s.push(10); s.push(20);s.push(30);s .push(40);
	cout << "栈的大小: " << s.size() << endl;
	//只要栈不为空,就查看栈顶,并且执行出栈操作
	while (!s.empty())//不为空
	{
		//查看栈顶元素
		cout << "栈顶元素为: " << s.top() << endl;
		//出栈
		s.pop();
	}
	cout << "栈的大小: " << s.size() << endl;
}
int main23()
{
	test24();
	system("pause");
	return 0;
}

3.6queue容器

3.6.1queue容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第6张图片

3.6.1queue基本概念/*

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

队列容器允许从一端新增元素,从另一端移除元素
队列中只有队头和队尾才可以被外界使用,因此队列不允许有遍历行为
队列中进数据称为–入队push
队列中出数据称为–出队pop
*/

3.6.2queue常用接口
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:栈容器常用的对外接口
构造函数:
queue que;                       //queue采用模板类实现,queue对象的默认构造
queue(const queue& que);            //拷贝构造函数
赋值操作:
queue& operator=(const queue& que); //重载等号操作符
数据存取:
push(elem);                         //往队尾添加元素
pop();                              //从对头移除第一个元素
back();                             //返回最后一个元素
front();                            //返回第一个元素
大小操作:
empty();                            //判断堆栈是否为空
size();                             //返回栈的大小
*/
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};
void test25()
{
	queue<Person>q;
	//准备数据
	Person p1("唐僧",1); Person p2("孙悟空", 2); Person p3("猪八戒", 3); Person p4("沙和尚", 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;
		//查看队尾
		cout << "队尾元素--姓名: " << q.back().m_Name << " 队尾元素--年龄: " << q.back().m_Age << endl;
		//出队
		q.pop();
	}
	cout << "队列大小为: " << q.size() << endl;
}
int main24()
{
	test25();
	system("pause");
	return 0;
}

3.7list容器

3.7.1list容器.jpg

Visual Studio 2022版本 B站黑马程序员C++自学分享-第三阶段(1)(主要包括:自己敲的代码、通过注释来备注上自己对代码的理解)_第7张图片

3.7.1list基本概念

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

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

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

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

优点:采用动态存储分配,不会造成内存浪费和溢出
可以对任意位置进行快速插入或删除元素(链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素)
缺点:链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大 (容器的遍历速度,没有数组快)
占用的空间比数组大

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

总结:STL中List和Vector是两个最常

3.7.2list构造函数
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:
创建list容器
函数原型:
list lst;           //list采用模板类实现,对象的默认构造形式
list(beg,end);         //构造函数将[beg,end)区间中的元素拷贝给本身
list(n,elem);          //构造函数将n个elem拷贝给本身
list(const list& lst); //拷贝构造函数
*/
void printList01(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test26()
{
	list<int>L1;
	//添加数据
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	//遍历容器
	printList01(L1);
	//区间方式构造
	list<int>L2(L1.begin(), L1.end());
	printList01(L2);
	//拷贝构造
	list<int>L3(L2);
	printList01(L3);
	//n个elem
	list<int>L4(10, 1000);
	printList01(L4);
}
int main25()//25
{
	test26();
	system("pause");
	return 0;
}
3.7.3list赋值和交换
#include 
using namespace std;
#include 
#include 
#include 
/*
list容器
功能描述:给list容器进行赋值,以及交换list容器
函数原型:
assign(beg,end);                  //将{beg,end)区间中的数据拷贝赋值给本身
assign(n,elem);                   //将n个elem拷贝赋值给本身
list& operator=(const list& lst); //重载等号操作符
swap(lst);                        //将lst与本身的元素互换
*/
void printList02(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test27()
{
	list<int>L1;
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	printList02(L1);
	//operator=赋值
	list<int>L2 = L1;
	printList02(L2);
	//assign赋值
	list<int>L3;
	L3.assign(L2.begin(),L2.end());
	printList02(L3);
	
	list<int>L4;
	L4.assign(10, 199);
	printList02(L4);
	//swap交换
	L4.swap(L1);
	cout << "交换后的L1" << endl;
	printList02(L1);
	cout << "交换后的L4" << endl;
	printList02(L4);
}
int main26()
{
	test27();
	system("pause");
	return 0;
}
3.7.4list大小操作
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:对list容器的大小进行操作
函数原型:
size();           //返回容器中元素的个数
empty();          //判断容器是否为空
resize();         //重新指定容器的长度为num,若容器变长,则以默认值填充新位置
                  //如果容器变短,则末尾超出容器长度的元素被删除
resize(num,elem); //重新指定容器的长度为num,若容器变长,则以elem填充新位置
                  //如果容器变短,则末尾超出容器长度的元素被删除
*/
void printList03(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test28()
{
	list<int>L1;
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	printList03(L1);
	//判断容器是否为空
	if (L1.empty())
	{
		cout << "L1为空" << endl;
	}
	else
	{
		cout << "L1不为空" << endl;
		cout << "L1的元素个数为: " << L1.size() << endl;

	}
	//重新指定大小
	L1.resize(10,9);
	printList03(L1);
	L1.resize(2);
	printList03(L1);
}
int main27()
{
	test28();
	system("pause");
	return 0;
}
3.7.5list插入和删除
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:对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值匹配的元素
*/
void printList04(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test29()
{
	list<int>L1;
	//尾插
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	//头插
	L1.push_front(100); L1.push_front(200); L1.push_front(300); L1.push_front(400);
	printList04(L1);
	//头删 尾删
	L1.pop_front(); L1.pop_back();
	printList04(L1);

	//insert插入
	L1.insert(L1.begin(), 1000);
	printList04(L1);
	
	list<int>::iterator it = L1.begin();
	L1.insert(++it, 100);
	printList04(L1);

	//erase删除
	it = L1.begin();
	L1.erase(++it);
	printList04(L1);

	//移除
	L1.push_back(10000);	L1.push_back(10000);	L1.push_back(10000);	L1.push_back(10000);
	printList04(L1);
	L1.remove(10000);
	printList04(L1);

	//清空
	L1.clear();
	printList04(L1);
}
int main28()
{
	test29();
	system("pause");
	return 0;
}
3.7.6list数据存取
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:对list容器中数据进行存取
函数原型:
front(); //返回第一个元素
back();  //返回最后一个元素
*/
void printList05(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test30()
{
	list<int>L1;
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	printList05(L1);
	//L1[0];//不可以用[]访问list容器中的元素
	//L1.at(0);//不可以用at方式访问list容器中的元素
	//原因是list本质是链表,不是用连续的线性空间存储数据
	//迭代器也是不支持随机访问的
	cout << "第一个元素为: " << L1.front() << endl;
	cout << "最后的元素为: " << L1.back() << endl;

	//验证迭代器是不支持随机访问的
	list<int>::iterator it = L1.begin();
	//支持双向(递增或递减)
	it++;
	it--;
	//it = it + 1;//没有重载操作运算符+或- , 不支持随机访问
}
int main29()
{
	test30();
	system("pause");
	return 0;
}
3.7.7list反转和排序
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:将容器中的元素反转,以及将容器中的数据进行排序
函数原型:
reverse(); //反转链表
sort();    //链表排序
*/
void printList06(const list<int>& L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
bool myCompare(int v1,int v2)
{
	//想要降序的话,就让第一个数 > 第二个数
	return v1 > v2;
}
void test31()
{
	list<int>L1;
	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
	printList06(L1);
	L1.reverse();
	printList06(L1);
	//sort(L1.begin(), L1.end());//所有不支持随机访问迭代器的容器,不可以使用标准算法
	//printList06(L1);

	//不支持随机访问迭代器的容器,内部会提供对应的一些算法
	L1.sort();//默认排序规则是从小到大的升序排列
	//sort()是一个成员函数
	printList06(L1);

	//降序
	L1.sort(myCompare);//注意返回的是一个bool类型
	printList06(L1);
}
int main30()
{
	test31();
	system("pause");
	return 0;
}
3.7.8排序案例
#include 
using namespace std;
#include 
#include 
#include 
/*
案例描述:将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
*/
/*
//void printList07(const list& L)
//{
//	for (list::const_iterator it = L.begin(); it != L.end(); it++)
//	{
//		cout << *it << " ";
//	}
//	cout << endl;
//}
//void test32()
//{
//	listL1;
//	L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40);
//	printList07(L1);
//}
*/
/*
对于自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序
高级排序只是在排序规则上再进行一次逻辑规则制定,并不复杂
*/
class Person
{
public:
	Person(string name, int age, int height)
	{
		this->m_Age = age;
		this->m_Height = height;
		this->m_Name = name;
	}
	string m_Name;
	int m_Age;
	int m_Height;
};
//指定排序规则
bool comparePerson(Person& p1,Person& p2)
{
	if (p1.m_Age == p2.m_Age)
	{
		//年龄相同 按身高降序
		return p1.m_Height > p2.m_Height;
	}
	else 
	{
		//按照年龄 升序
		return p1.m_Age < p2.m_Age;
	}
}
void test32()
{
	list<Person>L;//创建容器
	//准备数据
	Person p1("刘备", 35, 175); Person p2("曹操", 45, 180); Person p3("孙权", 40, 170);
	Person p4("赵云", 25, 190); Person p5("张飞", 35, 160); Person p6("关羽", 35, 200);
	//向容器中插入数据
	L.push_back(p1); L.push_back(p2); L.push_back(p3);
	L.push_back(p4); L.push_back(p5); L.push_back(p6);
	
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名: " << (*it).m_Name << " 年龄: " << (*it).m_Age << " 身高: " << it->m_Height << endl;
	}
	//排序
	cout << "--------------------------------------------------------" << endl;
	cout << "排序后: " << endl;
	L.sort(comparePerson);
	for (list<Person>::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名: " << (*it).m_Name << " 年龄: " << (*it).m_Age << " 身高: " << it->m_Height << endl;
	}
}
int main31()//31
{
	test32();
	system("pause");
	return 0;
}

3.8set/multiset容器

3.8.1set基本概念

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

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

set和multiset区别:
set不允许容器中有重复的元素
multiset允许容器中有重复的元素
*/

3.8.2set构造和赋值
#include 
using namespace std;
#include 
#include 
#include 	
/*
功能描述:创建set容器以及赋值

构造:
set st;                    //默认构造函数
set(const set& st);           //拷贝构造函数
赋值:
set& operator=(const set& st);//重载等号操作符
*/
void printSet01(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test33()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(30); s1.insert(40); //set容器不允许插入重复值s1.insert(20);
	printSet01(s1);
	//拷贝构造
	set<int>s2(s1);
	printSet01(s2);
	//等号赋值操作
	set<int>s3;
	s3 = s1;
	printSet01(s3);
}
int main32()//32
{
	test33();
	system("pause");
	return 0;
}
3.8.3set大小和交换
#include 
using namespace std;
#include 
#include 
#include 	
/*
功能描述:
统计set容器大小以及交换set容器
函数原型:
size();   //返回容器中元素的数目
empty();  //判断容器是否为空
swap(st); //交换两个集合容器
*/
void printSet02(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test34()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(30); s1.insert(40); //set容器不允许插入重复值s1.insert(20);
	printSet02(s1);

	//判断是否为空
	if (s1.empty())
	{
		cout << "s1为空" << endl;
	}
	else
	{
		cout << "s1不为空" << endl;
		cout << "s1中元素的数目: " << s1.size() << endl;
	}

	set<int>s2;
	s2.insert(20); s2.insert(35);;
	cout << "交换前:" << endl;
	cout << "s1:"; printSet02(s1);
	cout << "s2:"; printSet02(s2);

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

	s1.swap(s2);

	cout << "s1:"; printSet02(s1);
	cout << "s2:"; printSet02(s2);
}
int main33()//33
{
	test34();
	system("pause");
	return 0;
}
3.8.4set插入和删除
#include 
using namespace std;
#include 
#include 
#include 	
/*
功能描述:
set容器进行插入数据和删除数据
函数原型:
insert(elem);   //在容器中插入元素
clear();        //清除所有元素
erase(pos);     //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(elem);    //删除容器中值为elem的元素
*/
void printSet04(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test35()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(30); s1.insert(40);
	s1.insert(06); s1.insert(8); s1.insert(7); s1.insert(9);//set容器不允许插入重复值s1.insert(20);
	printSet04(s1);

	s1.erase(s1.begin());
	set<int>::iterator it = s1.begin();
	s1.erase(it++);
	printSet04(s1);

	s1.erase(40);
	printSet04(s1);

	s1.erase(s1.begin(), s1.end());//s1.clear();
	printSet04(s1);



}
int main34()//34
{
	test35();

	system("pause");
	return 0;
}
3.8.5set查找和统计
#include 
using namespace std;
#include 
#include 
#include 	
/*
功能描述:对set容器进行查找数据以及统计数据
函数原型:
find(key);  //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key); //统计key的元素个数
*/
void printSet05(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test36()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(30); s1.insert(40); //set容器不允许插入重复值s1.insert(20);
	printSet05(s1);

	set<int>::iterator pos = s1.find(30);
	if (pos != s1.end())
	{
		cout << "找到元素: " << *pos << endl;
		cout << "该元素个数为:" << s1.count(30) << endl;
	}
	else
	{
		cout << "未找到元素" << endl;
	}
}
int main35()//35
{
	test36();

	system("pause");
	return 0;
}
3.8.6set和multiset区别
#include 
using namespace std;
#include 
#include 
#include 	
/*
区别:
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
*/
void printSet06(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test37()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(30); s1.insert(40); //set容器不允许插入重复值s1.insert(20);
	//set
	pair<set<int>::iterator, bool> ret = s1.insert(50);
	if (ret.second)
	{
		cout << "插入成功" << endl;
	}
	else
	{
		cout << "插入失败" << endl;
	}

	printSet06(s1);

	ret = s1.insert(50);
	if (ret.second)
	{
		cout << "插入成功" << endl;
	}
	else
	{
		cout << "插入失败" << endl;
	}

	printSet06(s1);

	//multiset
	multiset<int>ms;
	ms.insert(10); ms.insert(10);
	for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main36()//36
{
	test37();

	system("pause");
	return 0;
}
3.8.7pair队组创建
#include 
using namespace std;
#include 
#include 
#include 	
/*
功能描述:成对出现的数据,利用对组可以返回两个数据

两种创建方式:
pair p (value1,value2);
pair p = make_pair(value1,value2);
*/
void printSet07(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test38()
{
	//队组的创建不需要头文件
	//第一种方式
	pair<string, int>p1("Tom", 19);
	cout << "姓名: " << p1.first << "  年龄:	" << p1.second << endl;

	//第二种方式
	pair<string, int>p2 = make_pair("Jerry", 29);
	cout << "姓名: " << p2.first << "  年龄:	" << p2.second << endl;
}
int main37()//37
{
	test38();

	system("pause");
	return 0;
}
3.8.9(1)set容器-内置类型指定排序规则
#include 
using namespace std;
#include 
#include 
#include 	
/*
学习目标:
set容器默认排序规则为从小到大,掌握如何改变排序规则
主要技术点:
利用仿函数,可以改变排序规则
*/
class MyCompare
{
public:
	bool operator()(int v1,int v2) const
	{
		return v1 > v2;
	}
};
void printSet08(set<int>& s)
{
	for (set<int>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

void test39()
{
	set<int>s1;
	//插入数据只有insert方式
	s1.insert(10); s1.insert(20); s1.insert(40); s1.insert(30); s1.insert(28); //插入之后不能更改排序规则
	//要更改排序规则应该在insert之前
	printSet08(s1);

	//指定排序规则为从大到小
	set<int, MyCompare>s2;
	s2.insert(22); s2.insert(32); s2.insert(12); s2.insert(52); s2.insert(42);
	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main38()//38
{
	test39();

	system("pause");
	return 0;
}
3.8.9(2)set容器-自定义数据类型指定排序规则
#include 
using namespace std;
#include 
#include 

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

//自定义数据类型都会指定排序规则
class comparePerson
{
public:
	bool operator()(const Person& p1, const Person& p2)const
	{
		//按照年龄降序
		return p1.m_Age > p2.m_Age;
	}
};
int main39()//39
{
	Person p1("刘备",11 ); Person p2("站法国",22 ); Person p3("g庙",32 ); Person p4("赵云", 52);
	set<Person,comparePerson>s;
	s.insert(p1);	s.insert(p2);
	s.insert(p3);
	s.insert(p4);
	
	for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << "姓名: " << it->m_Name << "     年龄: " << it->m_Age << endl;
	}
	cout << endl;
	
	system("pause");
	return 0;
}

3.9map/multimap容器

3.9.1map基本概念

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

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

优点:
可以根据key值快速找到value值

map和multimap区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素
*/

3.9.2map构造和赋值
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:
对map容器进行构造和赋值操作
函数原型:
构造: map mp;                 //map默认构造函数
       map(const map& mp);            //拷贝构造函数

赋值: map& operator=(const map& mp); //重载等号操作符
*/
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 test40()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));m.insert(pair<int, int>(4, 40));
	printMap(m);

	map<int, int>m2(m);
	printMap(m2);

	map<int, int>m3 = m2;
	printMap(m3);
}
int main40()
{
	test40();
	system("pause");
	return 0;
}
3.9.3map大小和交换
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:
统计map容器大小以及交换map容器

函数原型:
size();   //返回容器中元素的数目
empty();  //判断容器是否为空
swap(st); //交换两个集合容器
*/
void printMap02(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 test41()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30)); m.insert(pair<int, int>(4, 40));
	printMap02(m);

	if (m.empty())
	{
		cout << "m为空" << endl;
	}
	else
	{
		cout << "m不为空" << endl;
		cout << "m的大小为" << m.size() << endl;
	}

	map<int, int>m2;
	m2.insert(pair<int, int>(2, 4));
	m2.swap(m);
	printMap02(m2);
	printMap02(m);
}
int main41()//41
{
	test41();
	system("pause");
	return 0;
}
3.9.4map插入和删除
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:
map容器进行插入数据和删除数据

函数原型:
insert(elem);   //在容器中插入元素
clear();        //清除所有元素
erase(pos);     //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key);     //删除容器中值为key的元素
*/
void printMap03(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 test42()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	//插入
	//第一种
	m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30)); m.insert(pair<int, int>(4, 40));
	//第二种
	m.insert(make_pair(5, 50));
	//第三种
	m.insert(map<int, int>::value_type(6, 60));
	//第四种  该用途可以利用key访问到value
	m[7] = 70;//不建议使用
	printMap03(m);

	//删除
	m.erase(m.begin());
	printMap03(m);

	m.erase(5);
	printMap03(m);

	m.erase(m.begin(), m.end());//m.clear();
}
int main42()//42
{
	test42();
	system("pause");
	return 0;
}
3.9.5map查找和统计
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:
对map容器进行查找数据以及统计数据
函数原型:
find(key);   //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key);  //统计key的元素个数
*/
void printMap04(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 test43()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30)); m.insert(pair<int, int>(4, 40));
	printMap04(m);

	//查找
	map<int, int>::iterator pos = m.find(40);
	if (pos != m.end())
	{
		cout << "查到了元素 key = " << (*pos).first << "value = " << pos->second << endl;
	}
	else
	{
		cout << "未找到元素 " <<endl;
	}

	//统计
	//map不允许插入重复key元素,count统计而言 结果要么是0,要么是1
	//multimap的count统计可能大于1
	int num = m.count(3);
	cout << "num = " << num << endl;
}
int main43()//43
{
	test43();
	system("pause");
	return 0;
}
3.9.6map容器排序
#include 
using namespace std;
#include 
#include 
#include 

class myCompare
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;
	}
};
void printMap05(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 test44()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(3, 20));
	m.insert(pair<int, int>(2, 30)); m.insert(pair<int, int>(4, 40));
	printMap05(m);

	//修改排序规则
	//降序
	map<int, int, myCompare>m2;
	m2.insert(make_pair(1, 2)); m2.insert(make_pair(3, 4)); m2.insert(make_pair(5, 6)); m2.insert(make_pair(7, 8));
	for (map<int, int, myCompare>::iterator it = m2.begin(); it != m2.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;

}
int main44()//44
{
	test44();
	system("pause");
	return 0;
}

3.10案例-员工分组

#include 
using namespace std;
#include 
#include 
#include 

class myCompare
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;
	}
};
void printMap05(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 test44()
{
	//创建map容器
	map<int, int>m;

	//容器自动按value值进行排序
	m.insert(pair<int, int>(1, 10)); m.insert(pair<int, int>(3, 20));
	m.insert(pair<int, int>(2, 30)); m.insert(pair<int, int>(4, 40));
	printMap05(m);

	//修改排序规则
	//降序
	map<int, int, myCompare>m2;
	m2.insert(make_pair(1, 2)); m2.insert(make_pair(3, 4)); m2.insert(make_pair(5, 6)); m2.insert(make_pair(7, 8));
	for (map<int, int, myCompare>::iterator it = m2.begin(); it != m2.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;

}
int main44()//44
{
	test44();
	system("pause");
	return 0;
}

4.STL-函数对象

4.1函数对象

4.1.1函数对象概念

/*
概念:
重载函数调用操作符的类,其对象常称为函数对象
函数对象使用重载的()时,行为类似函数调用,也叫仿函数

本质:
函数对象(仿函数)是一个类,不是一个函数
*/

4.1.2函数对象使用
#include 
using namespace std;
#include 
/*
特点:
函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可以作为参数传递
*/

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=0;//内部自己状态
};

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

4.2谓词

4.2.1谓词概念

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

4.2.2一元谓词
#include 
using namespace std;
#include 

class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};
void test04()
{
	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}

	//查找容器中 有没有大于5的数字
	//GreaterFive()是匿名函数对象
	vector<int>::iterator it = find_if(v.begin(), v.end(),GreaterFive());//找到找不到都返回迭代器
	if (it == v.end())
	{
		cout << "未找到" << endl;
	}
	else
	{
		cout << "找到了大于5的数字: " << *it << endl;
	}
}
int main2()
{
	test04();
	system("pause");
	return 0;
}
4.2.3二元谓词
#include 
using namespace std;
#include 
#include 

class MyCompare
{
public:
	bool operator()(int val1, int val2)
	{
		return val1 > val2;
	}
};
void test05()
{
	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());
	cout << "----------------------------------------" << endl;
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main3()//3
{
	test05();
	system("pause");
	return 0;
}

4.3内建函数对象

4.3.1内建函数对象意义

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

分类:
算术仿函数
关系仿函数
逻辑仿函数

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

4.3.2算数仿函数
#include 
using namespace std;
#include 
#include 
/*
功能描述:
实现四则运算
其中negate是一元运算,其他都是二元运算

仿函数原型:
template T plus        //加法仿函数
template T minus       //减法仿函数
template T multiplies  //乘法仿函数
template T divides     //除法仿函数
template T modulus     //取模(取余数)仿函数
template T negate      //取反仿函数(除了取反仿函数是二元仿函数,其它都是一元仿函数)
*/
void test06()
{
	negate<int>n;
	cout << n(50) << endl;

	plus<int>p;
	cout << p(100, 1) << endl;

	modulus<int>m;
	cout << m(20, 3) << endl;
}
int main4()//4
{
	test06();
	system("pause");
	return 0;
}
4.3.3关系仿函数
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述:实现关系对比
仿函数原型:
template bool equal_to       //等于
template bool not_equal_to   //不等于
template bool greater        //大于
template bool greater_equal  //大于等于
template bool less           //小于
template bool less_equal     //小于等于
*/
class MyCompare
{
public:
	bool operator()(int v1, int v2)
	{
		return v1 > v2;
	}
};
void test07()
{
	vector<int>v;
	v.push_back(10); v.push_back(30); v.push_back(40); v.push_back(20); v.push_back(50);
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;

	//降序
	//sort(v.begin(),v.end(),MyCompare());
	//greater() 内建函数对象
	sort(v.begin(), v.end(), greater<int>());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
int main5()//5
{
	test07();
	system("pause");
	return 0;
}
4.3.4逻辑仿函数
#include 
using namespace std;
#include 
#include 
#include 
/*
功能描述: 实现逻辑运算
函数原型:
template bool logical_and  //逻辑与
template bool logical_or   //逻辑或
template bool logical_not  //逻辑非

逻辑仿函数实际应用较少,了解即可
*/
void test08()
{
	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 main6()//6
{
	test08();
	system("pause");
	return 0;
}

5.STL-常用算法

5.1常用遍历算法

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

算法简介:
for_each //遍历容器
transform //搬运容器到另一个容器中
*/

5.1.1for_each
#include 
using namespace std;
#include 
#include 
#include 
#include 
/*
功能描述: 实现遍历容器

函数原型:
for_each(iterator beg, iterator end, _func);
//遍历算法 遍历容器元素
//beg 开始迭代器
//end 结束迭代器
// _func 函数或者函数对象

for_each在实际开发中是最常用遍历算法,需要熟练掌握
*/

//普通函数
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 main1()
{
	test01();
	system("pause");
	return 0;
}
5.1.2transform
#include 
using namespace std;
#include 
#include 
#include 
#include 
/*
功能描述:搬运容器到另一个容器中
函数原型:
transform(iterator beg1,iterator end1,iterator beg2, _func);
//beg1 源容器开始迭代器
//end1 源容器结束迭代器
//beg2 目标容器开始迭代器
//_func 函数或者函数对象

*/
class Transform
{
public:
	int operator()(int v)
	{
		return v+1000;
	}
};

class MyPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test02()
{
	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 main2()
{
	test02();
	system("pause");
	return 0;
}

5.2常用查找算法

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

5.2.1find
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()

函数原型:
find(iterator beg,iterator end,value);
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
//beg 开始迭代器
//end 结束迭代器
//value 查找的元素

*/

//查找内置数据类型
void test03()
{
	vector<int>v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//查找容器中是否有 5 这个元素
	vector<int>::iterator it = find(v.begin(), v.end(), 10);
	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;
	}

	//重载 == 让底层find知道如何对比person数据类型
	bool operator==(const Person& p	)
	{
		if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	string m_Name;
	int m_Age;
};
//查找自定义数据类型
void test04()
{
	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);

	Person pp("bbb", 20);
	vector<Person>::iterator it = find(v.begin(), v.end(), pp);
	if (it == v.end())
	{
		cout << "未找到" << endl;
	}
	else
	{
		cout << "找到了," << "姓名为: " << it->m_Name << "  年龄为: " << it->m_Age << endl;
	}
}
int main3()
{
	test03();
	test04();
	system("pause");
	return 0;
}
5.2.2find_if
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
find_if(iterator beg,iterator end,_Pred);
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
//beg开始迭代器
//end结束迭代器
//_Pred 函数或者谓词(返回bool类型的仿函数)
*/
//查找内置数据类型
class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};
void test05()
{
	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 << "找到大于5的数字为: " << *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 test06()
{
	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);
	//找年龄大于20的人
	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 << " 的Person了" << endl;
	}
}
int main4()//4
{
	test05();
	test06();
	system("pause");
	return 0;
}
5.2.3adjacent_find
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:查找相邻重复元素

函数原型:
adjacent_find(iterator beg,iterator end);
//查找相邻重复元素,返回相邻元素的第一个位置的迭代器
//beg开始迭代器
//end结束迭代器
*/
void test07()
{
	vector<int>v;
	v.push_back(0); v.push_back(2); v.push_back(0); v.push_back(3); v.push_back(1); v.push_back(4); 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 main5()
{
	test07();
	system("pause");
	return 0;
}
5.2.4binary_search
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:查找指定元素是否存在
函数原型:
bool binary_search(iterator beg,iterator end,value);
//查找指定的元素,查到返回true,否则false
//注意:在无序序列中不可以使用
//beg 开始迭代器
//end 结束迭代器
//value 查找的元素

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

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

	//注意:在无序序列中不可以使用
	//v.push_back(2)
	
	//查找容器中是否有9的元素
	bool ret = binary_search(v.begin(), v.end(), 9);
	if (ret)
	{
		cout << "找到了元素 " << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}
}
int main6()
{
	test08();
	system("pause");
	return 0;
}
5.2.5count
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:统计元素个数
函数原型:
count(iterator beg;iterator end,value);
//统计元素出现次数
//beg 开始迭代器
//end 结束迭代器
//value 统计的元素
*/

//统计内置数据类型
void test09()
{
	vector<int>v;
	v.push_back(10); v.push_back(40); v.push_back(30); v.push_back(40); v.push_back(20); v.push_back(40);
	int num = count(v.begin(), v.end(), 40);
	cout << "40的元素个数为: " << num << endl;
}
//统计自定义数据类型
class Person
{
public:
	Person(string name,int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	//重载 == 号
	int operator==(const Person&p)
	{
		if (this->m_Age == p.m_Age)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	string m_Name;
	int m_Age;
};
void test10()
{
	vector<Person>v;
	Person p1("刘备", 35); Person p2("关羽", 35); Person p3("张飞", 30); Person p4("赵云", 35); Person p5("曹操", 35);
	//将人员插入到容器中
	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 << endl;
}
int main7()
{
	test09();
	test10();
	system("pause");
	return 0;
}
5.2.6count_if
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:按条件统计元素个数
函数原型:
count_if(iterator beg,iterator end,_Pred);
//按条件统计元素出现次数
//beg 开始迭代器
//end 结束迭代器
//_Pred 谓词
*/
//统计内置数据类型
class Greater20
{
public:
	bool operator()(int val)
	{
		return val > 20;
	}
};
void test11()
{
	vector<int>v;
	v.push_back(10); v.push_back(40); v.push_back(30); v.push_back(20); v.push_back(40); v.push_back(20);

	int num = count_if(v.begin(), v.end(), Greater20());
	cout << "大于20的元素个数为: " << 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 AgeGreater20
{
public:
	bool operator()(const Person& p)
	{
		return p.m_Age > 20;
	}
};
void test12()
{
	vector<Person>v;
	Person p1("刘备",35); Person p2("张飞", 35); Person p3("关羽", 35); Person p4("赵云", 40); Person p5("曹操", 20);
	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(), AgeGreater20());
	cout << "大于20岁的成员个数为: " << num << endl;
}
int main8()
{
	test11();
	test12();

	system("pause");
	return 0;
}

5.3常用排序算法

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

5.3.1sort
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
函数原型:
sort(iterator beg,iterator end,_Pred)
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
//beg  开始迭代器
//end  结束迭代器
//_Pred谓词
*/
void myPrint(int val)
{
	cout << val << " ";
}
void test13()
{
	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 main9()//9
{
	test13();

	system("pause");
	return 0;
}
5.3.2random_shuffle
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
#include 
/*
功能描述: 洗牌 指定范围内的元素随机调整次序
函数原型:
random_shuffle(iterator beg,iterator end);
//指定范围内的元素随机调整次序
//beg  开始迭代器
//end  结束迭代器
*/
void myPrint01(int val)
{
	cout << val << " ";
}
void test14()
{
	srand((unsigned int)time(NULL));//让打乱顺序更真实,要用到随机数种子

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

	//利用洗牌 算法 打乱顺序
	random_shuffle(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint01);
}
int main10()//10
{
	test14();
	cout << endl;
	system("pause");
	return 0;
}
5.3.3merge
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:两个容器元素合并,并存储到另一容器中
将两个有序序列结合到一起,又形成一个有序序列

函数原型:
merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
//容器元素合并,并存储到另一容器中
//注意:两个容器必须是有序的
//beg1 容器1开始迭代器
//end1 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
*/
void myPrint02(int val)
{
	cout << val << " ";
}
void test15()
{
	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(), myPrint02);
}
int main11()//11
{
	test15();

	system("pause");
	return 0;
}
5.3.4reverse
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
将容器内元素进行反转

reverse(iterator beg,iterator end);
//反转指定范围的元素
//beg开始迭代器
//end结束迭代器

面试题可能涉及到
*/
void myPrint03(int val)
{
	cout << val << " ";
}
void test16()
{
	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(), myPrint03);
	cout << endl;

	cout << "反转后: " << endl;
	reverse(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint03);
	cout << endl;

}
int main12()//12
{
	test16();

	system("pause");
	return 0;
}

5.4常用拷贝和替换算法

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

5.4.1copy
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
容器内指定范围的元素拷贝到另一容器中

函数原型:
copy(iterator beg, iterator end, iterator dest);
//按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
//beg  开始迭代器
//end  结束迭代器
//dest 目标起始迭代器
*/
void myPrint05(int val)
{
	cout << val << " ";
}
void test17()
{
	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(), myPrint05);
	cout << endl;
}
int main13()//13
{
	test17();

	system("pause");
	return 0;
}
5.4.2replace
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
将容器内指定范围的旧元素修改为新元素

函数原型:
replace(iterator beg,iterator end,oldvalue,newvalue);
//将区间内旧元素替换成新元素
//beg开始迭代器
//end结束迭代器
//oldvalue旧元素
//newvalue新元素
*/
class MyPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test18()
{
	vector<int>v;
	v.push_back(20); v.push_back(30); v.push_back(50); v.push_back(30);
	v.push_back(40); v.push_back(20); v.push_back(10); v.push_back(20);

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

	//将20替换为2000
	replace(v.begin(), v.end(), 20, 2000);
	for_each(v.begin(), v.end(), MyPrint());
	cout << endl;
}
int main14()//14
{
	test18();

	system("pause");
	return 0;
}
5.4.3replace_if
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
将区间内满足条件的元素,替换成指定元素

函数原型:
replace_if(iterator beg,iterator end,_pred,newvalue);
//按条件替换元素,满足条件的替换成指定元素
//beg  开始迭代器
//end  结束迭代器
//_pred    谓词
//newvalue 替换的新元素
*/
class MyPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};

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

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

	cout << "替换前: " << endl;
	for_each(v.begin(), v.end(),MyPrint());
	cout << endl;
	//将大于等于30 替换为3000
	replace_if(v.begin(), v.end(), Greater30(), 3000);
	cout << "替换后: " << endl;
	for_each(v.begin(), v.end(), MyPrint());
	cout << endl;
}

int main15()//15
{
	test19();

	system("pause");
	return 0;
}

5.4.4swap
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
互换两个容器的元素
(注意容器要同类型)
函数原型:
swap(container c1,container c2);
//互换两个容器的元素
//c1容器1
//c2容器2
*/
class MyPrint
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void Print(int val)
{
	cout << val << " ";
}
void test20()
{
	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(), Print);
	cout << endl;

	swap(v1, v2);
	cout << "交换后: " << endl;
	for_each(v1.begin(), v1.end(), MyPrint());
	cout << endl;
	for_each(v2.begin(), v2.end(), Print);
	cout << endl;
}
int main16()//16
{
	test20();

	system("pause");
	return 0;
}

5.5常用算术生成算法

/*
注意:算术生成算法属于小型算法,使用时包含的头文件为 #include
算法简介:
accumulate //计算容器元素累计总和
fill //向容器中添加元素
*/

5.5.1accumulate
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
函数原型:
accumulate(iterator beg,iterator end,value);
//计算容器元素累计总和(所有元素相加的和)

//beg    开始迭代器
//end    结束迭代器
//value  起时值
*/
void test21()
{
	vector<int>v;
	for (int i = 0; i <= 100; i++)
	{
		v.push_back(i);
	}

	int total = accumulate(v.begin(), v.end(), 0);//起始值从0开始,如果起始值为1000,那么总和就是5050+1000=6050

	cout << "total = " << total << endl;
}
int main17()//17
{
	test21();

	system("pause");
	return 0;
}
5.5.2fill
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
功能描述:
向容器中填充指定的值

函数原型:fill(iterator beg,iterator end,value);
//向容器中填充元素
//beg   开始迭代器
//end   结束迭代器
//value 填充的值
*/
void Print01(int val)
{
	cout << val << " ";
}
void test22()
{
	vector<int>v;
	v.resize(10);//默认值为0,扩容后就是10个0

	//后期重新填充
	fill(v.begin(), v.end(), 100);
	for_each(v.begin(), v.end(), Print01);
	cout << endl;

}
int main18()//18
{
	test22();

	system("pause");
	return 0;
}

5.6常用集合算法

/*
算法简介:
set_intersection //求两个容器的交集
set_union //求两个容器的并集
set_difference //就两个容器的差集
*/

5.6.1set_intersection
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
函数原型:
set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
//求两个集合的交集
//注意:两个集合必须是有序序列
//beg1 容器1开始迭代器
//end2 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
*/
void Print03(int val)
{
	cout << val << " ";
}
void test23()
{
	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()));//min()的调用需要 #include 

	//获取交集
	vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, Print03);
	//把itEnd改成vTarget.end()的话,后面会多出0,因为容量扩大了,而用itEnd的话就是标准的交集得出的结果

}
int main19()//19
{
	test23();
	cout << endl;

	system("pause");
	return 0;
}
5.6.2set_union
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
//求两个集合的交集
//注意:两个集合必须是有序序列
//beg1 容器1开始迭代器
//end2 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
*/
void Print06(int val)
{
	cout << val << " ";
}
void test24()
{
	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(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, Print06);//itEnd比vTarget.end()最后输出的并集更标准

}
int main20()//20
{
	test24();

	system("pause");
	return 0;
}
5.6.3set_difference
#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
/*
set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
//求两个集合的差集
//注意:两个集合必须是有序序列
//beg1 容器1开始迭代器
//end2 容器1结束迭代器
//beg2 容器2开始迭代器
//end2 容器2结束迭代器
//dest 目标容器开始迭代器
*/
void print(int val)
{
	cout << val << " ";
}
void test25()
{
	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()));//max()的调用需要 #include 

	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, print);//itEnd比vTarget.end()最后输出的差集更标准
	cout << endl;

	cout << "v2和v1的差集" << endl;
	itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, print);//itEnd比vTarget.end()最后输出的差集更标准
	cout << endl;

}
int main21()//21
{
	test25();

	system("pause");
	return 0;
}

6.演讲比赛流程管理系统

7.机房预约系统

你可能感兴趣的:(C++学习,c++,visual,studio,算法,开发语言,数据结构)