黑马程序员C++笔记——STL泛型编程VS2019

目录

1 函数模板 

1.1 函数模板基本语法

1.2 函数模板注意事项

1.3 函数模板案例—数组排序

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

1.5 普通函数与函数模板调用规则

1.6 模板的局限性

2 类模板

2.1 类模板语法

2.2 类模板和函数模板的区别

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

2.4 类模板对象做函数参数

2.5 类模板与继承

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

2.7 类模板分文件编写

2.8 类模板与友元

2.9 类模板案例—数组类封装  

3 STL初识

3.1 STL的基本概念

3.2 vector存放内置数据类型

3.3 vector存放自定义数据类型

3.4 容器嵌套容器 

4 string容器

4.1 构造函数 

4.2 赋值操作

4.3 字符串拼接 

4.4 字符串查找和拼接

4.5 字符串比较 

4.6 字符存取

4.7 字符串的插入和删除

4.8 子串获取

5 vector容器

5.1 构造函数

5.2 赋值操作

5.3 容量和大小

5.4 插入和删除

5.5 数据存取

5.6 互换容器

5.7 预留空间

6 deque容器

6.1 构造函数

6.2 赋值操作

6.3 大小操作

6.4 插入和删除

6.5 数据存取

6.6 排序操作

6.7 案例-评委打分

7 stack容器

8 queue 容器

9 list容器

9.1 基本概念

9.2 构造函数

9.3 赋值和交换 

 9.4 大小操作

9.5 插入和删除

9.6 数据存取

9.7 反转和排序

9.8 list容器排序案例

10 set/multiset容器

10.1 构造和赋值

10.2 大小和交换

10.3 插入和删除

10.4 查找和统计

10.5 set和multiset区别

10.6 pair对组创建使用

10.7 内置类型指定排序规则

10.8 自定义数据类型指定排序规则

11 map/multimap容器

11.1 构造和赋值

11.2  大小和交换

11.3 插入和删除

11.4 查找和统计

11.5 排序

12 STL案例—员工分工

13 函数对象—函数对象基本使用

14 谓词

14.1 一元谓词

14.2 二元谓词

15 内建函数对象

15.1 算术仿函数

15.2 关系仿函数

15.3 逻辑仿函数

16 常用遍历算法

16.1 for_each

16.2 transform

17 常用查找算法

17.1 find

17.2 find_if

17.3 adjacent_find

17.4 binary_search

17.5 count

17.6 count_if

18 常用排序算法

18.1 sort

18.2 random_shuffle

18.3 merge

18.4 reverse

19 常用拷贝和替换算法

19.1 copy

19.2 replace

19.3 replace_if

19.4 swap

20 常用算术生成算法

20.1 accumulate

20.2 fill

21 常用集合算法

21.1 set_intersection

21.2 set_union

21.3 set_difference

22 演讲比赛流程管理系统

23 机房预约系统

24 综合:搭配之前学的Qt做的通讯管理系统


1 函数模板 

1.1 函数模板基本语法

1、建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。

2、语法:

template//声明一个模板,T是一个通用的数据类型

函数声明或定义

#include 
using namespace std;
template//声明一个模板,T是一个通用的数据类型
void mySwap(T &a, T &b)//
{
	T temp = a;
	a = b;
	b = temp;
}
int main()
{
	int a = 10;
	int b = 20;
	// 自动类型推导:必须要推导出一致的数据类型 T,模板必须要确定出T的数据类型
	mySwap(a, b);
	// 显示指定类型
	mySwap(a,b);
	cout << a << b << endl;

}

1.2 函数模板注意事项

1、自动类型推导,必须推导出一致的数据类型T,才可以使用;

2、模板必须要确定出T的数据类型,才可以使用。

#include 
using namespace std;
template//typename可以替换成class
void mySwap(T &a, T &b)//
{
	T temp = a;
	a = b;
	b = temp;
}
void test01()
{
	int a = 0;
	int b = 0;
	char c = 'c';
	mySwap(a, b);
	//mySwap(a, c);错误,推导不出一致的T类型
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}
template
void func()
{
	cout << "func 调用" << endl;
}
void test02()
{
	//func(); 错误,没有指定出T
	func();
}
int main()
{	
	test01();
	test02();
}

1.3 函数模板案例—数组排序

1、实现一个通用 对数组进行排序的函数
2、规则 从大到小
3、算法 冒泡
4、测试数组 char数组 int数组 

#include 
using namespace std;
//实现一个通用 对数组进行排序的函数
//规则 从大到小
//算法 冒泡
//测试数组 char数组 int数组
template
void printArray(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}
/*template*///typename可以替换成class
//void mySwap(T& a, T& b)//
//{
//	T temp = a;
//	a = b;
//	b = temp;
//}不知道为什么,这里用这个交换没有办法排序
template
void mySort(T arr[],int len)
{
	for (int i = 0; i < len-1; i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			if (arr[j] < arr[j+1])
			{
				/*mySwap(arr[j], arr[i]);*/
				T temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;

			}
		}
	}
}
void test01()
{
	char charArr[] = "abcdef";
	int num = sizeof(charArr) / sizeof(char);
	mySort(charArr, num);
	printArray(charArr, num);
}
void test02()
{
	int intArray[] = { 0,3,4,6,2,8,9 };
	int num = sizeof(intArray) / sizeof(int);
	mySort(intArray, num);
	printArray(intArray, num);
}
int main()
{
	test01();
	test02();
	return 0;
}

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

1、普通函数调用可以发生隐式类型转换;

2、函数模板 用自动类型推导,不可以发生隐式类型转换

3、函数模板 用显示指定类型,可以发生隐式类型转换

#include
using namespace std;

int myAdd01(int a, int b)
{
	return a + b;
}
void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	cout << myAdd01(a, b) << endl;
	cout << myAdd01(a, c) << endl;//普通函数可以隐式转换
}
template
T myAdd02(T a, T b)
{
	return a + b;
}
void test02()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	cout << myAdd02(a, c) << endl;//
	//cout << myAdd02(a, c) << endl;//函数模板 用自动类型推导,不可以发生隐式类型转换
}
int main()
{
	test01();
	test02();
	return 0;
}

1.5 普通函数与函数模板调用规则

1、如果函数模板和普通函数都可以实现,优先调用普通函数

2、可以提高空模板参数列表来强制调用函数模板

3、函数模板也可以发生重载

4、如果函数模板可以产生更好的匹配,优先调用函数模板

#include
using namespace std;

void myPrint(int a, int b)//只有声明还是调用普通函数,而且报错
{
	cout << "调用普通函数" << endl;
}
template
void myPrint(T a, T b)
{
	cout << "调用函数模板" << endl;
}
template
void myPrint(T a, T b,T c)//重载的模板
{
	cout << "调用重载函数模板" << endl;
}
void test01()
{
	int a = 10, b = 20;
	//myPrint(a,b);// 优先调用普通函数
	
	// 通过空模板参数列表,强制调用函数模板
	myPrint<>(a, b);
	myPrint(a, b, 100);

	//如果函数模板可以产生更好的匹配,优先调用函数模板
	char c1 = 'a';
	char c2 = 'b';
	myPrint(c1, c2);//调用模板
}
int main()
{
	test01();
	return 0;
}

1.6 模板的局限性

模板不是万能的,有些特定数据类型,需要用具体化方式做特殊实现

利用具体化的模板,可以解决自定义类型的通用化

学习模板不是为了写模板,而是在STL能够运用系统提供的模板

#include
using namespace std;
#include
class Person
{
public:
	int m_age;
	string m_name;
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
};
template
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_name == p2.m_name && p1.m_age == p2.m_age)
	{
		return true;
	}
	else
	{
		return false;
	}
}
void test01()
{
	int a = 10;
	int b = 10;
	bool ret = myCompare(a, b);
	if (ret == true)
	{
		cout << "a=b" << endl;
	}
	else
	{
		cout << "a!=b" << endl;
	}
}
void test02()
{
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	bool ret = myCompare(p1, p2);
	if (ret == true)
	{
		cout << "p1=p2" << endl;
	}
	else
	{
		cout << "p1!=p2" << endl;
	}
}
int main()
{
	//test01();
	test02();
	return 0;
}

2 类模板

2.1 类模板语法

template

#include 
using namespace std;

template
class Person
{
public:
	NameType m_name;
	AgeType m_age;
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name = " << this->m_name << endl;
		cout << "age = " << this->m_age << endl;
	}
};
void test01()
{
	Person p1("Tom", 10);
	p1.showPerson();
}
int main()
{
	test01();
	return 0;
}

2.2 类模板和函数模板的区别

1、类模板没有自动类型推导使用方式

2、类模板在模板参数列表中可以有默认参数

#include 
using namespace std;
template//告诉了默认是int,后面可以不写int
class Person
{
public:
	NameType m_name;
	AgeType m_age;
	Person(NameType name, AgeType age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name = " << this->m_name << endl;
		cout << "age = " << this->m_age << endl;
	}
};
void test01()
{
	//Person p("Tom", 10);//错误,无法用自动类型推导
	Person p("Tom", 10);//正确

}
void test02()
{
	Person p("Tom", 10);
}
int main()
{
	test01();
	test02();
	return 0;
}

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

1、普通类中的成员函数一开始就可以创建

2、类模板中的成员函数在调用时才创建

#include 
using namespace std;

class Person1
{
public:
	void showPerson2()
	{
		cout << "Person1 show" << endl;
	}
};
class Person2
{
public:
	void showPerson2()
	{
		cout << "Person2 show" << endl;
	}
};
template
class Myclass
{
public:
	T obj;
	//类模板中的成员函数
	void func1()
	{
		obj.showPerson1;//没有报错
	}
	void func2()
	{
		obj.showPerson2;
	}
};
void test01()
{
	Myclassm;
	m.func1();
	//m.func2();调用的时候创建类模板成员函数
}
int main()
{
	test01();
	return 0;
}

2.4 类模板对象做函数参数

 类模板实例化出的对象作为函数参数怎么传

1、指定传入类型——直接显示对象的数据类型

2、参数模板化——将整个对象中的参数变为模板进行传递

3、整个类模板化——将这个对象类型 模板化进行传递

#include
using namespace std;

template
class Person
{
public:
	T1 m_name;
	T2 m_age;
	Person(T1 name, T2 age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name = " << this->m_name << endl;
		cout << "age = " << this->m_age << endl;
	}
};

// 1、指定传入类型——直接显示对象的数据类型
void printPerson1(Person&p)
{
	p.showPerson();
}
void test01()
{
	Personp("孙悟空", 100);
	printPerson1(p);
}

//2、参数模板化——将整个对象中的参数变为模板进行传递

template
void printPerson2(Person& p)
{
	p.showPerson();
	cout << "T1的类型为: " << typeid(T1).name() << endl;
	cout << "T2的类型为: " << typeid(T2).name() << endl;
}

void test02()
{
	Personp("猪八戒", 90);
	printPerson2(p);
}
//3、将整个类模板化
template
void printPerson3(T &p)
{
	p.showPerson();
	cout << "T的类型为: " << typeid(T).name() << endl;
}

void test03()
{
	Personp("唐僧", 30);
	printPerson3(p);
}
int main()
{
	test03();
	return 0;
}

2.5 类模板与继承

当类模板遇到继承时,需要注意以下几点

1、当子类继承父类是一个类模板时,子类在声明的时候,要指定出父类中的T的类型

2、如果不指定,编译器无法给子类分配内存

3、如果想灵活指定出父类中的T类型,子类也需变为类模板

#include
using namespace std;

template
class Base
{
	T m;
};
//class Son :public Base//错误,必须要知道父类中的T类型,才能继承给子类
class Son1 :public Base
{

};
void test01()
{
	Son1 s1;
}
//如果想灵活指定出父类中的T类型,子类也需变为类模板
template 
class Son2 :public Base
{
public:
	Son2()
	{
		cout << "T1的类型为: " << typeid(T1).name() << endl;
		cout << "T2的类型为: " << typeid(T2).name() << endl;
	}
	T1 obj;
};
void test02()
{
	Son2s2;//父类是int ,子类是char
}
int main()
{
	test02();
	return 0;
}

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

#include
using namespace std;

template
class Person
{
public:
	T1 m_name;
	T2 m_age;
	Person(T1 name, T2 age);
	void showPerson();
};
//构造函数类外实现
template
Person::Person(T1 name, T2 age)
{
	this->m_age = age;
	this->m_name = name;
}
//成员函数的类外实现
template
void Person::showPerson()
{
	cout << "姓名: " << this->m_name << "年龄: " << m_age << endl;
}
void test01()
{
	Personp("Tom", 20);
	p.showPerson();
}
int main()
{
	test01();
}

2.7 类模板分文件编写

问题: 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:

1、直接包含.cpp源文件

2、将声明和实习写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,不是强制的

#include 
using namespace std;
//1、直接包含源文件
//#include "person.cpp"
// 
//2、将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件
#include "person.hpp"

void test01()
{
	Personp("Jerry", 18);
	p.showPerson();
}
int main()
{
	test01();
	return 0;
}

2.8 类模板与友元

掌握类模板配合友元函数的类内实现和类外实现

1、全局函数类内实现—直接在类内声明友元即可

2、全局函数类外实现—需要提前让编译器自动全局函数的存在

#include
using namespace std;

//提前让编译器知道Person类存在
template
class Person;
template
void printPerson2(Personp)//类外实现
{
	cout << "姓名: " << p.m_name << " 年龄: " << p.m_age << endl;
}
//通过全局函数打印Person信息

template
class Person
{
	//全局函数 类内实现
	friend void printPerson(Personp)
	{
		cout << "姓名: " << p.m_name << " 年龄: " << p.m_age << endl;
	}
	//全局函数 类外实现,加空模版参数列表
	//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
	friend void printPerson2<>(Personp);
private:
	T1 m_name;
	T2 m_age;
public:
	Person(T1 name, T2 age)
	{
		this->m_age = age;
		this->m_name = name;
	}
};

void test01()
{
	Personp("John", 10);
	printPerson(p);
	printPerson2(p);
}

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

2.9 类模板案例—数组类封装  

拷贝构造函数是在构造的时候给对象赋初值用的,operate=运算符重载是构造函数完毕后要重新赋值的时候用的  

黑马程序员C++笔记——STL泛型编程VS2019_第1张图片

.hpp文件 

// 写一个通用的数组类
#pragma once
#include
using namespace std;

template
class MyArray
{
private:
	T* pAddress;//指针指向堆区开辟真实数组
	int m_Capacity;//数组的容量
	int m_Size;//数组的大小
public:
	MyArray()
	{
	}
	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 = new T[arr.m_Capacity];

		//将arr中的数据都拷贝过来
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}
	//operator防止浅拷贝问题 a=b=c;
	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 < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}
	//尾插法
	void Push_Back(const T& val)
	{
		//判断容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;
		this->m_Size++;
	}
	//尾删法
	void Pop_Back()
	{
		//让用户访问不到最后一个元素,逻辑删除
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}
	//通过下标访问数组中的元素
	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;
		}
	}
};

.cpp测试文件

#include
using namespace std;
#include "MyArray.hpp"
void printIntArray(MyArray& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << endl;
	}
}
void test01()
{
	MyArray arr1(5);//有参

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


	MyArrayarr2(arr1);//拷贝
	printIntArray(arr2);
	arr2.Pop_Back();//尾删
	cout << "arr2尾删后的打印输出为: " << endl;
	printIntArray(arr2);
	cout << "arr1的容量为: " << arr2.getCapacity() << endl;
	cout << "arr1的大小为: " << arr2.getSize() << endl;
	//MyArrayarr3(100);
	//arr3 = arr1;//operate=
}
//测试自定义数据类型
class Person
{
public:
	string m_name;
	int m_age;
	Person() {};//一定要写这个,不然会报错
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name = " << this->m_name << endl;
		cout << "age = " << this->m_age << endl;
	}
};
void printPersonArray(MyArray& arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << "姓名: "<< arr[i].m_name <<"年龄: "<< arr[i].m_age << endl;
	}
}
void test02()
{
	MyArrayarr(10);
	Person p1("孙悟空",999);
	Person p2("赵云", 45);
	Person p3("安其拉", 23);
	Person p4("韩信", 32);
	Person p5("妲己", 14);
	//将数据插入到数组
	arr.Push_Back(p1);
	arr.Push_Back(p2);
	arr.Push_Back(p3);
	arr.Push_Back(p4);
	arr.Push_Back(p5);
	printPersonArray(arr);
	cout << "arr的容量为: " << arr.getCapacity() << endl;
	cout << "arr的大小为: " << arr.getSize() << endl;
}
int main()
{
	//test01();
	test02();
	return 0;
}

3 STL初识

3.1 STL的基本概念

1、STL (Standard Template Library,标准模板库)

2、STL从广义上分为:容器container,算法algorithm,迭代器iterator

3、容器和算法之间通过迭代器进行无缝连接

4、STL几乎所有的代码都采用了模板类或者模板函数

STL的六大组件:容器、算法、迭代器,仿函数,适配器,空间配置

1.容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。

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

容器:置物之所也
STL容器就是将运用最广泛的一些数据结构实现出来常用的数据结构:数组,链表,树,栈,队列,集合,映射表等,这些容器分为序列式容器和关联式容器两种:
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。

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

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

迭代器:容器和算法之间粘合剂
提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针。
黑马程序员C++笔记——STL泛型编程VS2019_第2张图片

3.2 vector存放内置数据类型

容器:vector 算法:for_each 迭代器:vector::iterator

三种遍历方式

#include 
using namespace std;
#include 
#include //标准算法头文件

void myPrint(int val)//回调函数
{
	cout << val << endl;
}
void test01()
{
	//创建一个vector容器,数组
	vectorv;
	//向容器中插入数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	//通过迭代器访问容器中的数据
	vector::iterator itBegin = v.begin();//起始迭代器 指向容器中的第一个元素
	vector::iterator itEnd = v.end();//结束迭代器 指向容器中最后一个元素的下一个位置

	//第一种遍历方式
	while (itBegin != itEnd)
	{
		cout << *itBegin << endl;
		itBegin++;
	}

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

	//第三种遍历方式 利用STL提供的遍历算法
	for_each(v.begin(), v.end(), myPrint);

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

3.3 vector存放自定义数据类型

for (vector::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << "姓名: " << (*it)->m_name << " 年龄: " << (*it)->m_age << endl;
        //尖括号里是声明*it就是什么
    }

#include
using namespace std;
#include
class Person
{
public:
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	string m_name;
	int m_age;
};
void test01()
{
	vectorv;
	Person p1("aa", 10);
	Person p2("bb", 10);
	Person p3("cc", 10);
	Person p4("dd", 10);
	Person p5("ee", 10);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << (*it).m_name << " 年龄: " << (*it).m_age << endl;
		cout << "姓名: " << it->m_name<< " 年龄: " << it->m_age << endl;
	}
}
//存放自定义数据类型 指针
void test02()
{
	vectorv;
	Person p1("aa", 10);
	Person p2("bb", 20);
	Person p3("cc", 30);
	Person p4("dd", 40);
	Person p5("ee", 50);
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	v.push_back(&p4);
	v.push_back(&p5);
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名: " << (*it)->m_name << " 年龄: " << (*it)->m_age << endl;
		//尖括号里是声明*it就是什么
	}
}
int main()
{
	//test01();
	test02();
	return 0;
}

3.4 容器嵌套容器 

#include
using namespace std;
#include

void test01()
{
	vector>v;
	//先创建小容器
	vectorv1;
	vectorv2;
	vectorv3;
	vectorv4;
	//向小容器中添加数据
	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>::iterator it = v.begin(); it != v.end(); it++)
	{
		//*it是一个容器
		for (vector::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			cout << *vit << " ";
		}
		cout << endl;
	}
}
int main()
{
	test01();
	return 0;
}

4 string容器

4.1 构造函数 

黑马程序员C++笔记——STL泛型编程VS2019_第3张图片

黑马程序员C++笔记——STL泛型编程VS2019_第4张图片

#include 
using namespace std;

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

void test01()
{
	const char* str = "hello world";
	string s1;//默认构造
	string s2(str);
	string s3(s2);
	string s4(10, 'a');
	cout << "s2 = " << s2 << endl;
	cout << "s3 = " << s3 << endl;
	cout << "s4 = " << s4 << endl;
}
int main()
{
	test01();
	return 0;
}

4.2 赋值操作

黑马程序员C++笔记——STL泛型编程VS2019_第5张图片

#include 
using namespace std;

//string& operator=(const char* s);			char* 类型字符串赋值给当前的字符串
//string& operator=(const string& s);		把字符串s赋给当前的字符串
//string& operator=(char c);				字符赋值给当前的字符串
//string & assign(const char* s);			把字符串s赋给当前的字符串
//string& assign(const char* s, int n);		把字符串s的前n个字符赋给当前的字符串
//string& assign( const string &s );		把字符串s赋给当前字符串
//string& assign(int n, char c);			用n个字符c赋给当前字符串

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

	string s2 = s1;
	cout << s2 << endl;

	string s3;
	s3 = 'c';
	cout << s3 << endl;

	string s4;
	s4.assign("hello C++");
	cout << s4 << endl;

	string s5;
	s5.assign("hello C++", 5);
	cout << s5 << endl;

	string s6;
	s6.assign(s5);
	cout << s6 << endl;

	string s7;
	s7.assign(5, 'a');
}
int main()
{
	test01();
	return 0;
}

4.3 字符串拼接 

黑马程序员C++笔记——STL泛型编程VS2019_第6张图片

#include
using namespace std;
/*
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 test01()
{
	string str1 = "我";
	str1 += "不爱玩游戏,爱学习";
	cout << str1 << endl;
	str1 += ':';
	string str2 = "看柯南";
	str1 += str2;
	cout << str2 << endl;

	string str3 = "I";
	str3.append("love");
	cout << str3 << endl;
	str3.append(str2);
	cout << str3 << endl;
	string str4 = "learning aaa";
	str3.append(str4, 0, 8);
	cout << str3 << endl;
}
int main()
{
	test01();
	return 0;
}

4.4 字符串查找和拼接

黑马程序员C++笔记——STL泛型编程VS2019_第7张图片

#include
using namespace std;
//查找
void test01()
{
	string str1 = "abcdefgde";
	int pos1 = str1.find("de");
	int pos2 = str1.find("df");
	cout << pos1 << endl;
	cout << pos2 << endl;//没有找到字串返回 -1 
	//rfind 从右往左查,但是从左往右计算位置
	int pos3 = str1.rfind("de");
	cout << pos3 << endl;
}
//替换
void test02()
{
	string str1 = "Abcdefg";
	str1.replace(1, 3, "1111");//从1号位置起,替换为“1111”
	cout << str1 << endl;
}
int main()
{
	//test01();
	test02();
	return 0;
}

4.5 字符串比较 

黑马程序员C++笔记——STL泛型编程VS2019_第8张图片

#include
using namespace std;

void test01()
{
	string str1 = "hello";
	string str2 = "hello";
	if (str1.compare(str2) == 0)
	{
		cout << "str1 = str2" << endl;
	}
	else if(str1.compare(str2) > 0)
	{
		cout << "str1 > str2" << endl;
	}
	else
	{
		cout << "str1 < str2" << endl;
	}
}
int main()
{
	
	test01();
	return 0;
}

4.6 字符存取

黑马程序员C++笔记——STL泛型编程VS2019_第9张图片

#include
using namespace std;

void test01()
{
	string str1 = "hello";
	
	// 通过 [] 访问单个字符
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1[i] << " ";
	}
	cout << endl;
	//通过at方式访问单个字符
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1.at(i) << " ";
	}
	cout << endl;
	//修改单个字符
	str1[0] = 'x';
	cout << str1 << endl;
	str1.at(1) = 'x';
	cout << str1 << endl;
}
int main()
{
	test01();
	return 0;
}

4.7 字符串的插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第10张图片

#include
using namespace std;

void test01()
{
	string str = "hello";
	//插入
	str.insert(1, "123");// h123ello
	cout << str << endl;
	//删除
	str.erase(1, 3);
	cout << str << endl;// hello
}
int main()
{
	test01();
	return 0;
}

4.8 子串获取

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

#include
using namespace std;

void test01()
{
	string str = "abcdef";
	string subStr = str.substr(1, 3);
	cout << subStr << endl;// bcd
}
// 实用操作
void test02()
{
	string email = "[email protected]";
	// 从邮件地址中 获取用户信息
	int pos = email.find("@");
	string username = email.substr(0, pos);
	cout << username << endl;
}
int main()
{
	test02();
	return 0;
}

5 vector容器

5.1 构造函数

1、vector是单端数组,可以动态扩展

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

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

黑马程序员C++笔记——STL泛型编程VS2019_第11张图片

#include
using namespace std;
#include 
void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);

	vectorv2(v1.begin(), v1.end());
	printVector(v2);
	 
	vectorv3(10, 100);// 10 个100
	printVector(v3);

	vectorv4(v3);
	printVector(v4);
}

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

5.2 赋值操作

黑马程序员C++笔记——STL泛型编程VS2019_第12张图片

#include
using namespace std;
#include 
void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);

	vectorv2;
	v2 = v1;
	printVector(v2);

	vectorv3;
	v3.assign(v1.begin(), v1.end());
	printVector(v3);

	vectorv4;
	v4.assign(10,100);//赋值行为
	printVector(v4);
}

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

5.3 容量和大小

黑马程序员C++笔记——STL泛型编程VS2019_第13张图片

#include
using namespace std;
#include 
void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);

	if (v1.empty())// 为真 代表容器为空
	{
		cout << "v1 为空" << endl;
	}
	else
	{
		cout << "v1 不为空" << endl;
		cout << "v1的容量为:"<< v1.capacity() << endl;
		cout << "v1的大小为:" << v1.size() << endl;
	}
	// 重新指定大小
	v1.resize(15);
	printVector(v1);// 默认填充 0 
	v1.resize(17, 100);
	printVector(v1);// 填充100
	v1.resize(8);
	printVector(v1);// 删除后面的
}

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

5.4 插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第14张图片

#include
using namespace std;
#include 
/*
push_back(ele);										//尾部插入元素ele
pop_back( );										//删除最后一个元素
insert(const_iterator pos, ele);					//迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count,ele);			//迭代器指向位置pos插入count个元素
erase(const_iterator pos);							//删除迭代器指向的元素
erase(const_iterator start,const_iterator end);	//删除迭代器从start到end之间的元素
clear();											//删除容器中所有元素
*/
void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	//尾删
	v1.pop_back();
	printVector(v1);
	//插入 第一个参数是迭代器
	v1.insert(v1.begin(), 100);
	printVector(v1);
	v1.insert(v1.begin(), 3, 100);//在首部插入3个100
	printVector(v1);
	//删除
	v1.erase(v1.begin());
	printVector(v1);
	v1.erase(v1.begin(),v1.end());
	printVector(v1);
	//清空
	v1.clear();
}

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

5.5 数据存取

 黑马程序员C++笔记——STL泛型编程VS2019_第15张图片

#include
using namespace std;
#include 

void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1[i] << " ";
	}
	for (int i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << " ";
	}
	//获取第一个元素
	cout << v1.front() << endl;
	//获取最后一个元素
	cout << v1.back() << endl;
}

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

5.6 互换容器

实现两个容器内元素进行互换 swap(vec) 

#include
using namespace std;
#include 

void printVector(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);
	vectorv2;
	for (int i = 10; i >0; i--)
	{
		v2.push_back(i);
	}
	printVector(v2);
	
	cout << "交换后:" << endl;
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}
//实际用途 巧用swap可以收缩内存空间
void test02()
{
	vectorv;
	for (int i = 0; i < 100000; i++)
	{
		v.push_back(i);
	}
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;
	v.resize(3);//重新指定大小,但是没有改变容量
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;

	//利用swap收缩内存
	vector(v).swap(v);//vector(v)匿名对象,swap指针调换
	cout << "v的容量:" << v.capacity() << endl;
	cout << "v的大小:" << v.size() << endl;

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

5.7 预留空间

减少vector在动态扩展容量时扩展次数

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

#include
using namespace std;
#include 

void test01()
{
	vectorv;
	//利用reserve预留空间
	v.reserve(100000);
	int num = 0;
	int* p = NULL;
	for (int i = 0; i < 100000; i++)
	{
		v.push_back(i);
		if (p != &v[0])
		{
			p = &v[0];
			num++;
		}
	}
	cout << "num:" << num << endl;
}
int main()
{
	test01();
	return 0;
}

6 deque容器

6.1 构造函数

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

黑马程序员C++笔记——STL泛型编程VS2019_第16张图片

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

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

黑马程序员C++笔记——STL泛型编程VS2019_第17张图片

#include 
using namespace std;
#include
void printDeque(const deque&d)
{
	for (deque::const_iterator it = d.begin(); it != d.end(); it++)
	{
		//*it=100;容器中的数据不可以修改了
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	dequed1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque(d1);

	dequed2(d1.begin(), d1.end());
	printDeque(d2);

	dequed3(10, 100);
	printDeque(d3);

	dequed4(d3);
	printDeque(d4);
}
int main()
{
	test01();
	return 0;
}

6.2 赋值操作

6.3 大小操作

黑马程序员C++笔记——STL泛型编程VS2019_第18张图片

6.4 插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第19张图片

6.5 数据存取

黑马程序员C++笔记——STL泛型编程VS2019_第20张图片

#include 
using namespace std;
#include
void printDeque(const deque& d)
{
	for (deque::const_iterator it = d.begin(); it != d.end(); it++)
	{
		//*it=100;容器中的数据不可以修改了
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	dequed;
	
	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_front(100);
	d.push_front(200);
	printDeque(d);
	for (int i = 0; i < d.size(); i++)
	{
		cout << d.at(i) << " ";
	}
	cout << endl;
	cout << "第一个元素:" << d.front() << endl;
	cout << "最后一个元素:" << d.back() << endl;
}
int main()
{
	test01();
	return 0;
}

6.6 排序操作

对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序

#include 
using namespace std;
#include
#include
void printDeque(const deque& d)
{
	for (deque::const_iterator it = d.begin(); it != d.end(); it++)
	{
		//*it=100;容器中的数据不可以修改了
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	dequed;

	d.push_back(10);
	d.push_back(20);
	d.push_back(30);
	d.push_front(100);
	d.push_front(200);
	d.push_front(300);
	printDeque(d);
	
	//排序,
	sort(d.begin(), d.end());
	printDeque(d);
}
int main()
{
	test01();
	return 0;
}

6.7 案例-评委打分

黑马程序员C++笔记——STL泛型编程VS2019_第21张图片

#include 
using namespace std;
#include
#include
#include
class Person
{
public:
	Person(string n,int c)
	{
		name = n;
		score = c;
	}
	string name;
	int score;
};
void createPerson(vector&v)
{
	string nameSeed = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
		string name = "选手";
		name += nameSeed[i];

		int score = 0;

		Person p(name, score);
		v.push_back(p);
	}
}
void setScore(vector& v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		dequed;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 41 + 60;
			d.push_back(score);
		}

		//排序
		sort(d.begin(), d.end());
		//去除最高分和最低分
		d.pop_back();
		d.pop_front();
		//取平均分
		int sum = 0;
		for (deque::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			sum += *dit;
		}
		int avg = sum / d.size();
		//将平均分赋值选手上
		//(*it).score = avg;
		it->score = avg;
	}
}
void showScore(vector&v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		//cout << "姓名: " << (*it).name << " 平均分: " << (*it).score << endl;
		cout << "姓名: " << it->name << " 平均分: " << it->score << endl;
	}
}
int main()
{
	vectorv;//存放选手容器
	
	createPerson(v);
	
	setScore(v);
	showScore(v);
	return 0;
}

7 stack容器

先进后出,不可遍历

黑马程序员C++笔记——STL泛型编程VS2019_第22张图片

#include
#include
using namespace std;
void test01()
{
	stacks;
	s.push(10);
	s.push(20);
	s.push(30);
	s.push(40);
	s.push(50);
	while (!s.empty())
	{
		cout << s.top() << endl;
		s.pop();
	}
	cout << s.size();
}
int main()
{
	test01();
	return 0;
}

8 queue 容器

queue是一种先进先出的数据结构,只有队头队尾才可以被外界使用,因此队列也不允许遍历行为

黑马程序员C++笔记——STL泛型编程VS2019_第23张图片

#include
#include
using namespace std;
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
};
void test01()
{
	queueq;
	Person p1("孙悟空", 999);
	Person p2("猪八戒", 800);
	Person p3("唐僧", 40);
	Person p4("沙僧", 888);
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);
	cout << q.size();
	while (!q.empty())
	{
		cout << q.front().name <

9 list容器

9.1 基本概念

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

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

3、STL中的链表是一个双向循环列表

4、由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
5、list的优点:
·采用动态存储分配,不会造成内存浪费和溢出
·链表执行插入和删除操作十分方便,修改指针即可,不需要移动大星元素

6、list的缺点:
·链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大
List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。

黑马程序员C++笔记——STL泛型编程VS2019_第24张图片

9.2 构造函数

黑马程序员C++笔记——STL泛型编程VS2019_第25张图片

#include 
using namespace std;
#include

void printList(const list& L)
{
	for (list::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	listL1;
	//添加数据
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);//遍历容器
	//区间构造
	listL2(L1.begin(), L1.end());
	printList(L2);

	//拷贝构造
	listL3(L2);
	printList(L3);
	//n个elem
	listL4(10, 1000);
	printList(L4);
}

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

9.3 赋值和交换 

黑马程序员C++笔记——STL泛型编程VS2019_第26张图片

#include 
using namespace std;
#include

void printList(const list& L)
{
	for (list::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	listL1;
	//添加数据
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);//遍历容器
	
	listL2;
	L2 = L1;//=赋值
	printList(L2);

	listL3;
	L3.assign(L2.begin(), L2.end());
	printList(L3);

	listL4;
	L4.assign(10, 100);
	printList(L4);
}
void test02()//交换
{
	listL1;
	//添加数据
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	listL2;
	L2.assign(10, 100);
	cout << "交换前:" << endl;
	printList(L1);
	printList(L2);

	cout << "交换后:" << endl;
	L1.swap(L2);
	printList(L1);
	printList(L2);
}
int main()
{
	test02();
	return 0;
}

 9.4 大小操作

黑马程序员C++笔记——STL泛型编程VS2019_第27张图片

#include 
using namespace std;
#include

void printList(const list& L)
{
	for (list::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	listL1;
	//添加数据
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);//遍历容器

	//判断空
	if (L1.empty())
	{
		cout << "L1为空" << endl;
	}
	else
	{
		cout << "L1不为空" << endl;
		cout << "L1的元素个数:" << L1.size() << endl;
	}
	//重新指定大小
	L1.resize(10);
	printList(L1);
	L1.resize(12,100);
	printList(L1);
	L1.resize(2);
	printList(L1);
}

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

9.5 插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第28张图片

#include 
using namespace std;
#include

void printList(const list& L)
{
	for (list::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void test01()
{
	listL;
	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	
	//头插
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);
	printList(L);//遍历容器
	//尾删
	L.pop_back();
	printList(L);
	//头删
	L.pop_front();
	printList(L);

	//insert 插入200 1000 100 10 20
	list::iterator it = L.begin();
	L.insert(++it, 1000);
	printList(L);
	//删除1000 100 10 20
	it = L.begin();
	L.erase(it);
	printList(L);

	//移除
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);
	printList(L);
	L.remove(10000);
	printList(L);
}

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

9.6 数据存取

不能用 [ ] 和 at 访问list容器中的元素,list本质是链表,不是连续线性空间存储数据,迭代器也是不支持随机访问的。

#include 
using namespace std;
#include

void test01()
{
	listL;
	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	L.push_back(40);
	cout << "第一个元素为:" << L.front();
	cout << "第二个元素为:" << L.back();
	
	list::iterator it = L.begin();
	it++;
	it--;//支持双向
	//it=it+1;错误,不支持随机访问

}

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

9.7 反转和排序

黑马程序员C++笔记——STL泛型编程VS2019_第29张图片

#include 
using namespace std;
#include
void printList(const list& L)
{
	for (list::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
bool myCompare(int v1,int v2)
{
	//降序,就让第一个数大于第二个数
	return v1 > v2;
}
void test01()
{
	listL;
	//尾插
	L.push_back(10);
	L.push_back(30);
	L.push_back(70);
	L.push_back(20);
	L.push_back(50);
	cout << "反转前:" << endl;
	printList(L);
	cout << "反转后:" << endl;
	L.reverse();
	printList(L);
	//排序
	//所有不支持随机访问迭代器的容器,不可以用标准算法sort(L.begin(),L.end());是错的
	//不支持随机访问迭代器的容器,内部会提供一些算法
	cout << "排序后:" << endl;
	L.sort();//默认从小到大,升序
	printList(L);
	L.sort(myCompare);
	printList(L);
}
int main()
{
	test01();
	return 0;
}

9.8 list容器排序案例

将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高

排序规则:年龄升序,若年龄相同则按照身高进行降序

#include 
using namespace std;
#include
class Person
{
public:
	string m_Name;
	int m_Age;
	int m_Height;
	Person(string name,int age,int height)
	{
		m_Name = name;
		m_Age = age;
		m_Height = height;
	}
};
void printList(list& L)
{
	for (list::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名:" << it->m_Name << " 年龄:" << it->m_Age << " 身高:" << it->m_Height << endl;
	}
}
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 test01()
{
	listL;
	Person p1("刘备", 32, 175);
	Person p2("张飞", 35, 180);
	Person p3("关羽", 40, 190);
	Person p4("赵云", 35, 160);
	Person p5("曹操", 35, 170);
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	printList(L);
	cout << "-----------------------------------" << endl;
	cout << "排序后:" << endl;
	L.sort(comparePerson);
	printList(L);
}
int main()
{
	test01();
	return 0;
}

10 set/multiset容器

所有元素都会在插入时自动被排序,属于关联式容器,底层结构是用二叉树实现

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

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

10.1 构造和赋值

黑马程序员C++笔记——STL泛型编程VS2019_第30张图片

#include
using namespace std;
#include
void printSet(set&s)
{
	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
void test01()
{
	sets1;//没有push操作,只有insert方式
	s1.insert(10);
	s1.insert(20);
	s1.insert(30);
	s1.insert(40);
	s1.insert(30);
	//遍历
	//set容器特点:所有元素在插入的时候会自动被排序
	//不允许插入重复值
	printSet(s1);
	sets2(s1);//拷贝构造
	printSet(s2);
	//赋值
	sets3;
	s3 = s2;
	printSet(s3);
}
int main()
{
	test01();
	return 0;
}

10.2 大小和交换

黑马程序员C++笔记——STL泛型编程VS2019_第31张图片

#include
using namespace std;
#include
void printSet(set& s)
{
	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
void test01()
{
	sets1;//没有push操作,只有insert方式
	s1.insert(10);
	s1.insert(20);
	s1.insert(30);
	s1.insert(40);
	
	if (s1.empty())
	{
		cout << "s1为空" << endl;
	}
	else
	{
		cout << "s1不为空" << endl;
		cout << "元素个数:" << s1.size() << endl;
	}
	//交换
	sets2;
	s2.insert(100);
	s2.insert(200);
	s2.insert(300);
	s2.insert(400);
	cout << "交换前:" << endl;
	printSet(s1);
	printSet(s2);
	s1.swap(s2);
	cout << "交换后:" << endl;
	printSet(s1);
	printSet(s2);
}
int main()
{
	test01();
	return 0;
}

10.3 插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第32张图片

#include
using namespace std;
#include
void printSet(set& s)
{
	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
void test01()
{
	sets1;//没有push操作,只有insert方式
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(10);
	printSet(s1);
	//删除
	s1.erase(s1.begin());//删除了10
	printSet(s1);
	//删除某个具体的值
	s1.erase(30);
	printSet(s1);
	//清空
	s1.erase(s1.begin(), s1.end());
	printSet(s1);
	s1.clear();
	printSet(s1);
}
int main()
{
	test01();
	return 0;
}

10.4 查找和统计

#include
using namespace std;
#include

void test01()
{
	sets1;//没有push操作,只有insert方式
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(10);
	printSet(s1);
	set::iterator pos = s1.find(30);
	if (pos != s1.end())
	{
		cout << "找到元素:" << *pos << endl;
	}
	else
	{
		cout << "没有找到" << endl;
	}
	//统计30的个数
	int num = s1.count(30);
	//对于set而言,统计的结果要么是0要么是1
	cout << "num = " << num << endl;
}
int main()
{
	test01();
	return 0;
}

10.5 set和multiset区别

#include
using namespace std;
#include

void test01()
{
	sets1;
	pair::iterator, bool> ret = s1.insert(10);
	if (ret.second)
	{
		cout << "第一次插入成功" << endl;
	}
	else
	{
		cout << "第一次插入失败" << endl;
	}
	ret = s1.insert(10);
	if (ret.second)
	{
		cout << "第二次插入成功" << endl;
	}
	else
	{
		cout << "第二次插入失败" << endl;
	}
	multisetms;
	ms.insert(10);
	ms.insert(10);
	for (multiset::iterator it = ms.begin(); it != ms.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

10.6 pair对组创建使用

#include
using namespace std;

void test01()
{
	pairp("Tom",18);
	cout << "姓名:" << p.first << " 年龄:" << p.second << endl;

	pairp2 = make_pair("Jerry", 20);
	cout << "姓名:" << p2.first << " 年龄:" << p2.second << endl;
}
int main()
{
	test01();
	return 0;
}

10.7 内置类型指定排序规则

#include 
using namespace std;
#include
void printSet(set& s)
{
	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
class myCompare
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;
	}
};
void test01()
{
	sets1;
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(50);
	s1.insert(40);
	printSet(s1);
	//指定排序规则为从大到小
	sets2;
	s2.insert(10);
	s2.insert(30);
	s2.insert(20);
	s2.insert(50);
	s2.insert(40);
	for (set::iterator it = s2.begin(); it != s2.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}

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

10.8 自定义数据类型指定排序规则

#include 
using namespace std;
#include
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
};
class comparePerson
{
public:
	bool operator()(const Person &p1, const Person &p2)const
	{
		return p1.age > p2.age;
	}
};
void test01()
{
	//自定义数据类型 都会指定排序规则
	sets;
	Person p1("刘备", 24);
	Person p2("关羽", 32);
	Person p3("张飞", 35);
	Person p4("赵云", 37);
	s.insert(p1);
	s.insert(p2);
	s.insert(p3);
	s.insert(p4);
	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << "姓名:" << it->name << " 年龄:" << it->age << endl;
	}
	cout << endl;
}

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

11 map/multimap容器

1、map中所有元素都是pair

2、pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

3、所有元素都会根据元素键值自动排序

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

5、优点:可以根据键值快速找到value值

6、map中不允许容器中有重复key值元素,multimap允许容器中有重复key值元素

11.1 构造和赋值

#include
using namespace std;
#include
void printMap(map& m)
{
	for (map::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << (*it).first << " value = " << it->second << endl;
	}
	cout << endl;
}
void test01()
{
	mapm;
	m.insert(pair(1, 10));
	m.insert(pair(2, 20));
	m.insert(pair(3, 30));
	m.insert(pair(4, 40));
	printMap(m);
	mapm2(m);//拷贝构造
	printMap(m2);
	mapm3;
	m3 = m;
	printMap(m3);

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

11.2  大小和交换

黑马程序员C++笔记——STL泛型编程VS2019_第33张图片

#include
using namespace std;
#include
void printMap(map& m)
{
	for (map::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << (*it).first << " value = " << it->second << endl;
	}
	cout << endl;
}
void test01()
{
	mapm;
	m.insert(pair(1, 10));
	m.insert(pair(2, 20));
	m.insert(pair(3, 30));
	m.insert(pair(4, 40));
	
	if (m.empty())
	{
		cout << "m为空" << endl;
	}
	else
	{
		cout << "m不为空" << endl;
		cout << "m的大小为:" << m.size() << endl;
	}
	//交换
	mapm2;
	m.insert(pair(5, 100));
	m.insert(pair(6, 200));
	m.insert(pair(7, 300));
	m.insert(pair(8, 400));
	cout << "交换前:" << endl;
	printMap(m);
	printMap(m2);
	cout << "交换后:" << endl;
	m.swap(m2);
	printMap(m);
	printMap(m2);
}
int main()
{
	test01();
	return 0;
}

11.3 插入和删除

黑马程序员C++笔记——STL泛型编程VS2019_第34张图片

#include
using namespace std;
#include
void printMap(map& m)
{
	for (map::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << (*it).first << " value = " << it->second << endl;
	}
	cout << endl;
}
void test01()
{
	mapm;
	m.insert(pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(map::value_type(3, 30));
	m[4] = 40;
	//cout << m[5] << endl;// []不建议插入,可以利用key访问value
	//确定key存在,找到value值
	printMap(m);
	//删除
	m.erase(m.begin());
	printMap(m);
	m.erase(3);//只按照key删除
	printMap(m);
	
	m.erase(m.begin(), m.end());//区间删
	printMap(m);
	m.clear();
	printMap(m);
}
int main()
{
	test01();
	return 0;
}

11.4 查找和统计

#include
using namespace std;
#include
void test01()
{
	mapm;
	m.insert(pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(map::value_type(3, 30));
	m.insert(make_pair(3, 40));
	map::iterator pos = m.find(3);
	if (pos != m.end())
	{
		cout << "查找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
	}
	else
	{
		cout << "未找到" << endl;
	}
	//统计
	int num = m.count(3);//num只能为0,1
	cout << "num = " << num << endl;
}
int main()
{
	test01();
	return 0;
}

11.5 排序

#include
using namespace std;
#include

class myCompare
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;//仿函数
	}
};
void test01()
{
	mapm;
	m.insert(pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(map::value_type(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));
	for (map::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << (*it).first << " value = " << it->second << endl;
	}
	cout << endl;
	
}
int main()
{
	test01();
	return 0;
}

12 STL案例—员工分工

黑马程序员C++笔记——STL泛型编程VS2019_第35张图片

#include
using namespace std;
#include
#include
#include
#include
#define CEHUA  0
#define MEISHU 1
#define YANFA  2
class Worker
{
public:
	string name;
	int salary;
};
void createWorker(vector&v)
{
	string nameSeed = "ABCDEFGHIJ";
	for (int i = 0; i < 10; i++)
	{
		Worker worker;
		worker.name = "员工";
		worker.name += nameSeed[i];
		worker.salary = rand() % 10000 + 10001;//10000~20000
		v.push_back(worker);//将员工放入容器中
	}
}
void setGroup(vector& v, multimap& m)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		//产生随机部门编号
		int deptId = rand() % 3;//0 1 2
		//将员工插入到分组中
		m.insert(make_pair(deptId, *it));
	}
}
void showWorkerByGroup(multimap& m)
{
	cout << "策划部门:" << endl;
	multimap::iterator pos = m.find(CEHUA);
	int count = m.count(CEHUA);
	int index = 0;
	for (; pos != m.end() && index < count; index++, pos++)
	{
		cout << "姓名:" << pos->second.name << " 工资:" << pos->second.salary << endl;
	}

	cout << "---------------------------------------" << endl;
	cout << "研发部门:" << endl;
	pos = m.find(YANFA);
	count = m.count(YANFA);
	index = 0;
	for (; pos != m.end() && index < count; index++, pos++)
	{
		cout << "姓名:" << pos->second.name << " 工资:" << pos->second.salary << endl;
	}

	cout << "---------------------------------------" << endl;
	cout << "美术部门:" << endl;
	pos = m.find(MEISHU);
	count = m.count(MEISHU);
	index = 0;
	for (; pos != m.end() && index < count; index++, pos++)
	{
		cout << "姓名:" << pos->second.name << " 工资:" << pos->second.salary << endl;
	}
}
int main()
{
	srand((unsigned int)time(NULL));//随机数种子
	//创建员工
	vectorvWorker;
	createWorker(vWorker);
	//测试
	/*for (vector::iterator it = vWorker.begin(); it != vWorker.end(); it++)
	{
		cout << "姓名:" << it->name << " 工资:" << it->salary << endl;
	}*/
	//分组
	multimapmWorker;
	setGroup(vWorker,mWorker);
	
	//分组显示员工
	showWorkerByGroup(mWorker);
	return 0;
}

13 函数对象—函数对象基本使用

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

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

函数对象的使用:

函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;

函数对象超出普通函数的概念,函数对象可以有自己的状态;

函数对象可以作为参数传递;

#include
using namespace std;
//1、可以像普通函数那样调用,可以有参数,可以有返回值;
class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};
void test01()
{
	MyAdd myAdd;
	cout << myAdd(10, 10);
}

//2、超出普通函数的概念,函数对象可以有自己的状态;
class MyPrint
{
public:
	MyPrint()
	{
		this->count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl;
		this->count++;
	}
	int count;//内部自己的状态
};
void test02()
{
	MyPrint myPrint;
	myPrint("hello world");
	myPrint("hello world");
	myPrint("hello world");
	myPrint("hello world");
	cout << "MyPrint调用次数为:" << myPrint.count << endl;
}

//3、函数对象可以作为参数传递;
void doPrint(MyPrint& mp, string test)
{
	mp(test);
}
void test03()
{
	MyPrint myPrint;
	doPrint(myPrint, "Hello c++!");
}
int main()
{
	test03();
	return 0;
}

14 谓词

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

如果operator()接受两个参数,那么叫做二元谓词

14.1 一元谓词

#include
using namespace std;
#include
#include
class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}	
};
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	// 查找容器中有没有大于5的数字 
	// GreaterFive()匿名对象
	vector::iterator it;
	it = find_if(v.begin(), v.end(), GreaterFive());
	if (it == v.end())
	{
		cout << "未找到" << endl;
	}
	else
	{
		cout << "找到了大于5的数字 " << endl;
		cout << *it << endl;
	}
}

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

14.2 二元谓词

#include
using namespace std;
#include
#include
class MyCompare
{
public:
	bool operator()(int v1,int v2)
	{
		return v1 > v2;
	}
};
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(40);
	v.push_back(50);
	v.push_back(30);
	v.push_back(30);
	sort(v.begin(), v.end());
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
	//使用函数对象 改变算法测量
	sort(v.begin(), v.end(), MyCompare());
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}

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

15 内建函数对象

STL内建了一些函数对象

#include

15.1 算术仿函数

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

黑马程序员C++笔记——STL泛型编程VS2019_第36张图片

#include
using namespace std;
#include
void test01()
{
	// negate 取反
	negaten;
	cout << n(20) << endl;
	plusp;
	cout << p(1, 1) << endl;
}

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

15.2 关系仿函数

黑马程序员C++笔记——STL泛型编程VS2019_第37张图片

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

void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(30);
	v.push_back(50);
	v.push_back(40);
	v.push_back(20);
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
	sort(v.begin(), v.end(), greater());
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

15.3 逻辑仿函数

黑马程序员C++笔记——STL泛型编程VS2019_第38张图片

#include
using namespace std;
#include
#include
#include
void test01()
{
	vectorv;
	v.push_back(true);
	v.push_back(false);
	v.push_back(true);
	v.push_back(true);
	v.push_back(false);
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
	//利用逻辑非,将容器v搬运到容器v2中,并且执行取反
	vectorv2;
	v2.resize(v.size());
    //搬运
	transform(v.begin(), v.end(), v2.begin(), logical_not());
	for (vector::iterator it = v2.begin(); it != v2.end(); it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

16 常用遍历算法

黑马程序员C++笔记——STL泛型编程VS2019_第39张图片

16.1 for_each

for_each(iterator beg, iterator_end,_func);

起始迭代器,结束迭代器,函数(普通函数,仿函数)

#include
using namespace std;
#include
#include
void print01(int val)
{
	cout << val << " ";
}
class print02
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	for_each(v.begin(), v.end(), print01);
	cout << endl;

	for_each(v.begin(), v.end(), print02());//仿函数,创建匿名对象处理
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

16.2 transform

搬运容器到另一个容器

transform(iterator beg, iterator_end, iterator beg2, _func);

源容器起始迭代器,源容器结束迭代器,目标容器起始迭代器,函数(普通函数,仿函数)

#include
using namespace std;
#include
#include

class Transform
{
public:
	int operator()(int v)
	{
		return v + 100;
	}
};
class print01
{
public:
	void operator()(int val)
	{
		cout << val << " ";
	}
};
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	vectorvTarget;
	vTarget.resize(v.size());
	transform(v.begin(), v.end(), vTarget.begin(), Transform());
	for_each(vTarget.begin(), vTarget.end(), print01());
}
int main()
{
	test01();
	return 0;
}

17 常用查找算法

黑马程序员C++笔记——STL泛型编程VS2019_第40张图片  

17.1 find

find(iterator beg, iterator_end, value);

起始迭代器,结束迭代器,查找的元素

返回迭代器

#include
using namespace std;
#include
#include
//查找 内置数据类型
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//查找容器中是否有 5 
	vector::iterator it = find(v.begin(), v.end(), 5);
	if (it == v.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了" << *it << endl;
	}
}
//查找 自定义数据类型
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
	//重载 == 让底层find知道如何对比Person类型
	bool operator==(const Person& p)
	{
		if (this->name == p.name && this->age == p.age)
		{
			return true;
		}
		else
			return false;
	}
};
void test02()
{
	vectorv;
	Person p1("aaa", 12);
	Person p2("bbb", 23);
	Person p3("ccc", 34);
	Person p4("ddd", 45);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	
	Person pp("bbb", 23);
	vector::iterator it = find(v.begin(), v.end(), pp);
	if (it == v.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了" << "姓名:" << it->name << " 年龄:" << it->age << endl;
	}
}
int main()
{
	test02();
	return 0;
}

17.2 find_if

find(iterator beg, iterator_end, _Pred);

起始迭加器,结束迭加器,_Pred函数或者谓词(返回bool类型的仿函数)

返回迭代器

#include
using namespace std;
#include
#include
//查找 内置数据类型
class GreaterFive
{
public:
	bool operator()(int v)
	{
		return v > 5;
	}
};
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	vector::iterator it = find_if(v.begin(), v.end(), GreaterFive());
	if (it == v.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了大于5的数字:" << *it << endl;
	}
}
//查找 自定义数据类型
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
};
class Greater20
{
public:
	bool operator()(Person& p)
	{
		return p.age > 30;
	}
};
void test02()
{
	vectorv;
	Person p1("aaa", 12);
	Person p2("bbb", 23);
	Person p3("ccc", 34);
	Person p4("ddd", 45);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);

	Person pp("bbb", 23);
	vector::iterator it = find_if(v.begin(), v.end(), Greater20());
	if (it == v.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了年龄大于30的人:" << "姓名:" << it->name << " 年龄:" << it->age << endl;
	}
}
int main()
{
	test02();
	return 0;
}

17.3 adjacent_find

adjacent_find(iterator beg, iterator_end);

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

#include
using namespace std;
#include
#include
void test01()
{
	vectorv;
	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(4);
	v.push_back(3);
	v.push_back(3);
	vector::iterator it = adjacent_find(v.begin(), v.end());
	if (it == v.end())
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了相邻重复元素:" << *it << endl;//4
	}
}

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

bool binary_search(iterator beg, iterator_end, value);

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

在无序序列中不可用

#include
using namespace std;
#include
#include
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);//必须是有序升序数列
	}
	//v.push_back(2);无序则结果未知
	bool ret = binary_search(v.begin(), v.end(),9);
	if (!ret)
	{
		cout << "没有找到" << endl;
	}
	else
	{
		cout << "找到了9元素" << endl;
	}
}

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

17.5 count

count(iterator beg, iterator_end, value);

统计元素出现次数,返回int类型数据,value统计的元素

#include
using namespace std;
#include
#include
//查找 内置数据类型
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(20);
	v.push_back(40);
	v.push_back(30);
	v.push_back(10);
	int num = count(v.begin(), v.end(), 10);
	cout << "10的个数为:" << num << endl;
}
//查找 自定义数据类型
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
	//重载 == 
	bool operator==(const Person& p)
	{
		if (this->age== p.age)
		{
			return true;
		}
		else
			return false;
	}
};
void test02()
{
	vectorv;
	Person p1("aaa", 12);
	Person p2("bbb", 13);
	Person p3("ccc", 13);
	Person p4("ddd", 45);
	Person p5("eee", 45);
	Person p6("fff", 45);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	v.push_back(p6);
	Person pp("ggg", 45);
	int num = count(v.begin(), v.end(), pp);
	cout << "和pp同岁的人有:" << num << " 个" << endl;
}
int main()
{
	test02();
	return 0;
}

17.6 count_if

count_if(iterator beg, iterator_end, _Pred);按条件统计元素个数

返回 int 

#include
using namespace std;
#include
#include
//查找 内置数据类型
class Greater20
{
public:
	bool operator()(int val)
	{
		return val > 20;
	}
};
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(20);
	v.push_back(40);
	v.push_back(30);
	v.push_back(50);
	int num = count_if(v.begin(), v.end(), Greater20());
	cout << "大于20的元素个数为:" << num << endl;
}
//查找 自定义数据类型
class Person
{
public:
	string name;
	int age;
	Person(string n, int a)
	{
		name = n;
		age = a;
	}
};
class AgeGreater20
{
public:
	bool operator()(const Person& p)
	{
		return p.age > 20;
	}
};
void test02()
{
	vectorv;
	Person p1("aaa", 12);
	Person p2("bbb", 13);
	Person p3("ccc", 13);
	Person p4("ddd", 24);
	Person p5("eee", 40);
	Person p6("fff", 45);
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
	v.push_back(p6);
	int num = count_if(v.begin(), v.end(), AgeGreater20());
	cout << "统计年龄大于20的个数为:" << num << " 个" << endl;
}
int main()
{
	test02();
	return 0;
}

18 常用排序算法

黑马程序员C++笔记——STL泛型编程VS2019_第41张图片

18.1 sort

sort(iterator beg, iterator_end, _Pred);

如果不填_Pred则默认从小到大排序,写了就按照所写方法排序

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

class Greater20
{
public:
	bool operator()(int val)
	{
		return val > 20;
	}
};
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(20);
	v.push_back(40);
	v.push_back(30);
	v.push_back(50);
	//默认升序
	sort(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	//降序
	sort(v.begin(), v.end(), greater());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

18.2 random_shuffle

random_shuffle(iterator beg, iterator_end);

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

#include
using namespace std;
#include
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	srand((unsigned int)time(NULL));//随机种子
	vectorv;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);
	//默认
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	//打乱
	random_shuffle(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	
	test01();
	return 0;
}

18.3 merge

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

merge(iterator beg1, iterator_end1, iterator beg2, iterator_end2, iterator dest beg);

两个容器必须是有序的;

#include
using namespace std;
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);
	vectorv2;
	v2.push_back(1);
	v2.push_back(2);
	v2.push_back(3);
	v2.push_back(4);
	v2.push_back(60);

	vectorvTarget;
	//提前给目标容器分配空间
	vTarget.resize(v.size() + v2.size());
	merge(v.begin(), v.end(),v2.begin(),v2.end(),vTarget.begin());
	for_each(vTarget.begin(), vTarget.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

18.4 reverse

reverse(iterator beg, iterator_end);

反转指定范围元素

#include
using namespace std;
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	v.push_back(10);
	v.push_back(30);
	v.push_back(20);
	v.push_back(50);
	v.push_back(40);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	reverse(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

19 常用拷贝和替换算法

黑马程序员C++笔记——STL泛型编程VS2019_第42张图片

19.1 copy

copy(iterator beg, iterator_end, iterator dest beg);

#include
using namespace std;
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	vectorv2;
	v2.resize(v.size());
	copy(v.begin(), v.end(), v2.begin());
	for_each(v2.begin(), v2.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

19.2 replace

replace(iterator beg, iterator_end, old value, new value);

将区间内的所有旧元素替换为新元素

#include
using namespace std;
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	replace(v.begin(), v.end(), 2, 1);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

19.3 replace_if

 replace_if(iterator beg, iterator_end, _Pred, new value);按条件替换

#include
using namespace std;
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};
void test01()
{
	vectorv;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	//大于5的都替换为100
	replace_if(v.begin(), v.end(), GreaterFive(), 100);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

19.4 swap

swap(container c1, container c2);

互换两个容器元素

#include
using namespace std;
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	vectorv1;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
		v1.push_back(i + 100);
	}
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	for_each(v1.begin(), v1.end(), myPrint);
	cout << endl;
	cout << "交换后:" << endl;
	swap(v, v1);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
	for_each(v1.begin(), v1.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

20 常用算术生成算法

黑马程序员C++笔记——STL泛型编程VS2019_第43张图片

20.1 accumulate

accumulate(iterator beg, iterator_end,value);

计算区间容器元素累积总和,value为起始值

#include
using namespace std;
#include
#include
#include
void test01()
{
	vectorv;
	for (int i = 0; i <= 100; i++)
	{
		v.push_back(i);
	}
	// 第三个参数为起始累加值
	int total = accumulate(v.begin(), v.end(), 0);
	cout << total << endl;
}
int main()
{
	test01();
	return 0;
}

20.2 fill

fill(iterator beg, iterator_end,value);将指定区间填充元素

#include
using namespace std;
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv;
	v.resize(10);
	fill(v.begin(), v.end(), 10);
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

21 常用集合算法

黑马程序员C++笔记——STL泛型编程VS2019_第44张图片

21.1 set_intersection

set_intersection(iterator beg1, iterator_end1, iterator beg2, iterator_end2, iterator dest beg)

求两个容器交集,返回交集最后一个迭代器

两个集合必须为有序序列

#include
using namespace std;
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv1;
	vectorv2;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
		v2.push_back(i + 5);
	}
	vectorvTarget;
	vTarget.resize(min(v1.size(), v2.size()));
	vector::iterator itFind = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itFind, myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

21.2 set_union

set_union(iterator beg1, iterator_end1, iterator beg2, iterator_end2, iterator dest beg)

求两个容器并集,返回并集最后一个迭代器

两个集合必须为有序序列

#include
using namespace std;
#include
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv1;
	vectorv2;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
		v2.push_back(i + 5);
	}
	vectorvTarget;
	vTarget.resize(v1.size() + v2.size());
	vector::iterator itFind = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itFind, myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

21.3 set_difference

 set_difference(iterator beg1, iterator_end1, iterator beg2, iterator_end2, iterator dest beg)

求两个容器差集,返回差集最后一个迭代器

两个集合必须为有序序列

#include
using namespace std;
#include
#include
void myPrint(int val)
{
	cout << val << " ";
}
void test01()
{
	vectorv1;
	vectorv2;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
		v2.push_back(i + 5);
	}
	vectorvTarget;
	//最特殊情况,两个容器没有交集 取两个容器中大的作为容器开辟空间
	vTarget.resize(max(v1.size(), v2.size()));
	cout << "v1和v2的差集为:" << endl;
	vector::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint);
	cout << endl;
	cout << "v2和v1的差集为:" << endl;
	itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
	for_each(vTarget.begin(), itEnd, myPrint);
	cout << endl;
}
int main()
{
	test01();
	return 0;
}

22 演讲比赛流程管理系统

演讲比赛流程管理系统 提取码:02tl

23 机房预约系统

机房预约系统VS提取码: wv9t

24 综合:搭配之前学的Qt做的通讯管理系统

 通讯录管理系统 提取码: uruv

你可能感兴趣的:(c++,算法,开发语言)