The fifth stage: C++ improves programming

Video link: https://www.bilibili.com/video/BV1et411b73Z/This
note: P167-263

C++ improves programming

  • This stage mainly focuses on C++Generic programmingandSTLExplain the technology in detail and explore the deeper use of C++

1 template

1.1 The concept of template

Templates are used to create universal molds , greatly improving reusability.

For example, templates in life

One-inch photo template:

Insert image description here

PPT template:

Insert image description here
Insert image description here

Template features:

  • The template cannot be used directly, it is just a framework
  • Templates are universal but not omnipotent

1.2 Function template

  • Another programming idea in C++ is calledGeneric programming, the main technology used is templates

  • C++ provides two template mechanisms: function templates and class templates

1.2.1 Function template syntax

Function template function:

Create a general function whose function return value type and formal parameter type do not have to be specified and are represented by a virtual type .

grammar:

template<typename T>
函数声明或定义

explain:

template—Declaration to create a template

typename— It appears that the symbol behind it is a data type and can be replaced by class.

T— Common data type, name can be replaced, usually in uppercase letters

Example:


//交换整型函数
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>
void mySwap(T& a, T& b)
{
    
    
	T temp = a;
	a = b;
	b = temp;
}

void test01()
{
    
    
	int a = 10;
	int b = 20;
	
	//swapInt(a, b);

	//利用模板实现交换
	//1、自动类型推导
	mySwap(a, b);

	//2、显示指定类型
	mySwap<int>(a, b);

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Function templates use the keyword template
  • There are two ways to use function templates:automatic type inferenceShow specified type
  • The purpose of templates is to improve reusability and parameterize types

1.2.2 Notes on function templates

Precautions:

  • Automatic type derivation must deduce a consistent data type T before it can be used.

  • The template must determine the data type of T before it can be used

Example:

//利用模板提供通用的交换函数
template<class T>
void mySwap(T& a, T& b)
{
    
    
	T temp = a;
	a = b;
	b = temp;
}


// 1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test01()
{
    
    
	int a = 10;
	int b = 20;
	char c = 'c';

	mySwap(a, b); // 正确,可以推导出一致的T
	//mySwap(a, c); // 错误,推导不出一致的T类型
}


// 2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{
    
    
	cout << "func 调用" << endl;
}

void test02()
{
    
    
	//func(); //错误,模板不能独立使用,必须确定出T的类型
	func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}

int main() {
    
    

	test01();
	test02();

	system("pause");

	return 0;
}

Summarize:

  • When using templates, you must determine the common data type T and be able to deduce a consistent type

1.2.3 Function template case

Case description:

  • Use function templates to encapsulate a sorting function, which can sort arrays of different data types.
  • The sorting rule is from large to small, and the sorting algorithm is selection sort.
  • Test using char array and int array respectively

Example:

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


template<class T> // 也可以替换成typename
//利用选择排序,进行对数组从大到小的排序
void mySort(T arr[], int len)
{
    
    
	for (int i = 0; i < len; i++)
	{
    
    
		int max = i; //最大数的下标
		for (int j = i + 1; j < len; j++)
		{
    
    
			if (arr[max] < arr[j])
			{
    
    
				max = j;
			}
		}
		if (max != i) //如果最大数的下标不是i,交换两者
		{
    
    
			mySwap(arr[max], arr[i]);
		}
	}
}
template<typename T>
void printArray(T arr[], int len) {
    
    

	for (int i = 0; i < len; i++) {
    
    
		cout << arr[i] << " ";
	}
	cout << endl;
}
void test01()
{
    
    
	//测试char数组
	char charArr[] = "bdcfeagh";
	int num = sizeof(charArr) / sizeof(char);
	mySort(charArr, num);
	printArray(charArr, num);
}

void test02()
{
    
    
	//测试int数组
	int intArr[] = {
    
     7, 5, 8, 1, 3, 9, 2, 4, 6 };
	int num = sizeof(intArr) / sizeof(int);
	mySort(intArr, num);
	printArray(intArr, num);
}

int main() {
    
    

	test01();
	test02();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summary: Templates can improve code reuse and require proficiency.

1.2.4 The difference between ordinary functions and function templates

The difference between ordinary functions and function templates:

  • Automatic type conversion (implicit type conversion) can occur when calling ordinary functions
  • When a function template is called, if automatic type deduction is used, implicit type conversion will not occur.
  • Implicit type conversion can occur if the specified type is explicitly specified

Example:

//普通函数
int myAdd01(int a, int b)
{
    
    
	return a + b;
}

//函数模板
template<class T>
T myAdd02(T a, T b)  
{
    
    
	return a + b;
}

//使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换
void test01()
{
    
    
	int a = 10;
	int b = 20;
	char c = 'c';
	
	cout << myAdd01(a, c) << endl; //正确,将char类型的'c'隐式转换为int类型  'c' 对应 ASCII码 99

	//myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换

	myAdd02<int>(a, c); //正确,如果用显示指定类型,可以发生隐式类型转换
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summary: It is recommended to use the method of displaying the specified type and calling the function template, because you can determine the general type T by yourself

1.2.5 Calling rules for ordinary functions and function templates

The calling rules are as follows:

  1. If both function templates and ordinary functions can be implemented, ordinary functions will be called first.
  2. Function templates can be forced to be called with an empty template parameter list
  3. Function templates can also be overloaded
  4. If the function template can produce a better match, the function template is called first

Example:

//普通函数与函数模板调用规则
void myPrint(int a, int b)
{
    
    
	cout << "调用的普通函数" << endl;
}

template<typename T>
void myPrint(T a, T b) 
{
    
     
	cout << "调用的模板" << endl;
}

template<typename T>
void myPrint(T a, T b, T c) 
{
    
     
	cout << "调用重载的模板" << endl; 
}

void test01()
{
    
    
	//1、如果函数模板和普通函数都可以实现,优先调用普通函数
	// 注意 如果告诉编译器  普通函数是有的,但只是声明没有实现,或者不在当前文件内实现,就会报错找不到
	int a = 10;
	int b = 20;
	myPrint(a, b); //调用普通函数

	//2、可以通过空模板参数列表来强制调用函数模板
	myPrint<>(a, b); //调用函数模板

	//3、函数模板也可以发生重载
	int c = 30;
	myPrint(a, b, c); //调用重载的函数模板

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary: Since function templates are provided, it is best not to provide ordinary functions, otherwise ambiguity will easily occur.

1.2.6 Limitations of templates

limitation:

  • The universality of templates is not a panacea

For example:

	template<class T>
	void f(T a, T b)
	{
    
     
    	a = b;
    }

The assignment operation provided in the above code cannot be implemented if the incoming a and b are an array.

Another example:

	template<class T>
	void f(T a, T b)
	{
    
     
    	if(a > b) {
    
     ... }
    }

In the above code, if the data type of T is passed in a custom data type like Person, it will not work properly.

Therefore, in order to solve this problem, C++ provides template overloading, which can provide specific templates for these specific types.

Example:

#include<iostream>
using namespace std;

#include <string>

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;
	}
}


//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
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 = 20;
	//内置数据类型可以直接使用通用的函数模板
	bool ret = myCompare(a, b);
	if (ret)
	{
    
    
		cout << "a == b " << endl;
	}
	else
	{
    
    
		cout << "a != b " << endl;
	}
}

void test02()
{
    
    
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	//自定义数据类型,不会调用普通的函数模板
	//可以创建具体化的Person数据类型的模板,用于特殊处理这个类型
	bool ret = myCompare(p1, p2);
	if (ret)
	{
    
    
		cout << "p1 == p2 " << endl;
	}
	else
	{
    
    
		cout << "p1 != p2 " << endl;
	}
}

int main() {
    
    

	test01();

	test02();

	system("pause");

	return 0;
}

Summarize:

  • Use specific templates to solve the generalization of custom types
  • Learning templates is not to write templates, but to be able to use the templates provided by the system in STL

1.3 Class template

1.3.1 Class template syntax

Class template function:

  • Create a general class. The data types of the members in the class do not need to be specified and can be represented by a virtual type .

grammar:

template<typename T>

explain:

template — declare a template to be created

typename - indicates that the symbol behind it is a data type and can be replaced by class

T — General data type, name can be replaced, usually uppercase letters

Example:

#include <string>
//类模板
template<class NameType, class AgeType> 
class Person
{
    
    
public:
	Person(NameType name, AgeType age)
	{
    
    
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
    
    
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

void test01()
{
    
    
	// 指定NameType 为string类型,AgeType 为 int类型
	Person<string, int>P1("even", 23);
	P1.showPerson();
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The syntax of class templates and function templates are similar. Add a class after the declaration template template. This type is called a class template.

1.3.2 The difference between class templates and function templates

There are two main differences between class templates and function templates:

  1. There is no way to use automatic type inference in class templates
  2. Class templates can have default parameters in the template parameter list

Example:

#include <string>
//类模板
template<class NameType, class AgeType = int> 
class Person
{
    
    
public:
	Person(NameType name, AgeType age)
	{
    
    
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
    
    
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

//1、类模板没有自动类型推导的使用方式
void test01()
{
    
    
	// Person p("孙悟空", 1000); // 错误 类模板使用时候,不可以用自动类型推导
	Person <string ,int>p("孙悟空", 1000); //必须使用显示指定类型的方式,使用类模板
	p.showPerson();
}

//2、类模板在模板参数列表中可以有默认参数
void test02()
{
    
    
	Person <string> p("猪八戒", 999); //类模板中的模板参数列表 可以指定默认参数
	p.showPerson();
}

int main() {
    
    

	test01();

	test02();

	system("pause");

	return 0;
}

Insert image description here

Insert image description here

Summarize:

  • Class templates can only be used to display specified types.
  • The template parameter list in a class template can have default parameters

1.3.3 Timing of creating member functions in class templates

Member functions in class templatesandMember functions in ordinary classesThe creation timing is different:

  • Member functions in ordinary classes can be created from the beginning
  • Member functions in class templates are created when called

Example:

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 fun1() {
    
     obj.showPerson1(); }
	void fun2() {
    
     obj.showPerson2(); }

};

void test01()
{
    
    
	MyClass<Person1> m;
	
	m.fun1();

	//m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summary: Member functions in class templates are not created at the beginning, they are created only when they are called.

1.3.4 Class template objects as function parameters

learning target:

  • The object instantiated by the class template, the way to pass parameters to the function

A total ofThree input methods

  1. Specify the type passed in - directly displays the data type of the object
  2. Parameter templating —turn parameters in objects into templates for passing
  3. Entire class templated — Template this object type to pass

Example:

#include <string>
//类模板
template<class NameType, class AgeType = int> 
class Person
{
    
    
public:
	Person(NameType name, AgeType age)
	{
    
    
		this->mName = name;
		this->mAge = age;
	}
	void showPerson()
	{
    
    
		cout << "name: " << this->mName << " age: " << this->mAge << endl;
	}
public:
	NameType mName;
	AgeType mAge;
};

//1、指定传入的类型
void printPerson1(Person<string, int> &p) 
{
    
    
	p.showPerson();
}
void test01()
{
    
    
	Person <string, int >p("孙悟空", 100);
	printPerson1(p);
}

//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
    
    
	p.showPerson();
	cout << "T1的类型为: " << typeid(T1).name() << endl;
	cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{
    
    
	Person <string, int >p("猪八戒", 90);
	printPerson2(p);
}

//3、整个类模板化
template<class T>
void printPerson3(T & p)
{
    
    
	cout << "T的类型为: " << typeid(T).name() << endl;
	p.showPerson();

}
void test03()
{
    
    
	Person <string, int >p("唐僧", 30);
	printPerson3(p);
}

int main() {
    
    

	test01();
	test02();
	test03();

	system("pause");

	return 0;
}
  • 1. Specify the incoming type
    Insert image description here
    Insert image description here
  • 2. Parameter templating
    Insert image description here
  • 3. Template the entire class
    Insert image description here

Summarize:

  • Objects created through class templates can pass parameters to functions in three ways:
  • The first one is more widely used: specify the type passed in

1.3.5 Class templates and inheritance

When class templates encounter inheritance, you need to pay attention to the following points:

  • When the parent class inherited by a subclass is a class template , the subclass must specify the type of T in the parent class when declaring it.
  • If not specified , the compiler cannot allocate memory to the subclass
  • If you want to flexibly specify the type of T in the parent class, the subclass also needs to become a class template.

Example:

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

//class Son:public Base  //错误,c++编译需要给子类分配内存,必须知道父类中T的类型才可以向下继承
class Son :public Base<int> //必须指定一个类型
{
    
    
};
void test01()
{
    
    
	Son c; // 编译成功的
}

//如果想灵活指定出父类中T的类型,子类也需变为类模板
//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
{
    
    
public:
	Son2()
	{
    
    
		cout << typeid(T1).name() << endl;
		cout << typeid(T2).name() << endl;
	}
};

void test02()
{
    
    
	Son2<int, char> child1;
}


int main() {
    
    

	test01();

	test02();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summary: If the parent class is a class template, the subclass needs to specify the data type of T in the parent class

1.3.6 Out-of-class implementation of class template member functions

Learning goal: Be able to master the out-of-class implementation of member functions in class templates

Example:

#include <string>

//类模板中成员函数类外实现
template<class T1, class T2>
class Person {
    
    
public:
	//成员函数类内声明
	Person(T1 name, T2 age);
	void showPerson();

public:
	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 << " 年龄:" << this->m_Age << endl;
}

void test01()
{
    
    
	Person<string, int> p("Tom", 20);
	p.showPerson();
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: When the member function in a class template is implemented outside the class, a template parameter list needs to be added.

1.3.7 Class templates are written in separate files

learning target:

  • Master the problems and solutions caused by writing class template member functions in separate files

question:

  • The member function in the class template is created during the calling phase, resulting in failure to link when writing in separate files.

solve:

  • Solution 1: Directly include the .cpp source file
  • Solution 2: Write the declaration and implementation into the same file, and change the suffix to .hpp . hpp is an agreed name and is not mandatory.

Example 1:
Insert image description here

Example 2:

Code in person.hpp:

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

template<class T1, class T2>
class Person {
    
    
public:
	Person(T1 name, T2 age);
	void showPerson();
public:
	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 << " 年龄:" << this->m_Age << endl;
}

Class templates are divided into files to write code in .cpp

#include<iostream>
using namespace std;

//#include "person.h"
#include "person.cpp" //解决方式1,包含cpp源文件

//解决方式2,将声明和实现写到一起,文件后缀名改为.hpp
#include "person.hpp"
void test01()
{
    
    
	Person<string, int> p("Tom", 10);
	p.showPerson();
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary: The mainstream solution is the second one , which is to write the class template member functions together and change the suffix name to .hpp

1.3.8 Class templates and friends

learning target:

  • Master the in-class and out-of-class implementation of class templates and friend functions

Global function implementation within the class - just declare friends directly within the class

Global function implementation outside the class - the compiler needs to know the existence of the global function in advance

Example:

#include <string>

//2、全局函数配合友元  类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元

//提前让编译器知道Person类的存在
template<class T1, class T2> 
class Person;
// 类外实现
template<class T1, class T2>
void printPerson2(Person<T1, T2> & p)
{
    
    
	cout << "类外实现 ---- 姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
    
    
	//1、全局函数配合友元   类内实现
	friend void printPerson(Person<T1, T2> & p)
	{
    
    
		cout << "姓名: " << p.m_Name << " 年龄:" << p.m_Age << endl;
	}


	//全局函数配合友元  类外实现
	//加空模版参数列表<>
	//如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
	//【就是类外实现写到上方,让编译器先看到】
	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;

};

//1、全局函数在类内实现
void test01()
{
    
    
	Person <string, int >p("Tom", 20);
	printPerson(p);
}

//2、全局函数在类外实现
void test02()
{
    
    
	Person <string, int >p("Jerry", 30);
	printPerson2(p);
}

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: It is recommended that global functions be implemented within classes, which are simple to use and can be directly recognized by the compiler.

1.3.9 Class template case

Case description: To implement a general array class, the requirements are as follows:

  • Can store data of built-in data types and custom data types
  • Store data in the array into the heap area
  • The capacity of the array that can be passed in the constructor
  • Provide corresponding copy constructor and operator= to prevent shallow copy problems
  • Provides tail insertion and tail deletion methods to add and delete data in the array
  • Elements in an array can be accessed through subscripts
  • You can get the current number of elements in the array and the capacity of the array

Insert image description here

Example:

Code in myArray.hpp

//自己的通用数组类
#pragma once
#include <iostream>
using namespace std;

template<class T>
class MyArray
{
    
    
public:
    
	//构造函数 有参构造
	MyArray(int capacity)
	{
    
    
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];
	}

	//拷贝构造
	MyArray(const MyArray & arr)
	{
    
    
		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++)
		{
    
    
			//如果T为对象,而且还包含指针,必须需要重载 = 操作符,因为这个等号不是 构造 而是赋值,
			// 普通类型可以直接= 但是指针类型需要深拷贝
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	//重载= 操作符  防止浅拷贝问题
	MyArray& operator=(const MyArray& myarray) {
    
    
		//先判断原来堆区是否有数据,如果有先释放
		if (this->pAddress != NULL) {
    
    
			delete[] this->pAddress;
			this->m_Capacity = 0;
			this->m_Size = 0;
			this->pAddress = NULL;
		}
		// 深拷贝 
		this->m_Capacity = myarray.m_Capacity;
		this->m_Size = myarray.m_Size;
		this->pAddress = new T[myarray.m_Capacity];
		for (int i = 0; i < this->m_Size; i++) {
    
    
			//this->pAddress[i] = myarray[i];
			this->pAddress[i] = myarray.pAddress[i];
		}
		return *this; //自身返回
	}
	
	//通过下标方式访问数组中的元素 arr[]
	//重载[] 操作符  arr[0]
	T& operator [](int index)
	{
    
    
		return this->pAddress[index]; //不考虑越界,用户自己去处理
	}

	//尾插法
	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;
		}
		//直接长度-1,访问不到最后元素,逻辑删除
		this->m_Size--; 
	}

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

	//获取数组大小
	int	getSize()
	{
    
    
		return this->m_Size;
	}


	//析构
	~MyArray()
	{
    
    
		if (this->pAddress != NULL)
		{
    
    
			delete[] this->pAddress; //释放
			this->pAddress = NULL; //置空 防止野指针	
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}

private:
	T * pAddress;  //指针指向一个堆空间,这个空间存储真正的数据
	int m_Capacity; //容量
	int m_Size;   // 大小
};

Insert image description here
Insert image description here

Class template case— array class encapsulation.cpp

#include "myArray.hpp"
#include <string>

void printIntArray(MyArray<int>& arr) {
    
    
	for (int i = 0; i < arr.getSize(); i++) {
    
    
		cout << arr[i] << " ";
	}
	cout << endl;
}

//测试内置数据类型
void test01()
{
    
    
	MyArray<int> array1(10);
	for (int i = 0; i < 10; i++)
	{
    
    
		array1.Push_back(i);
	}
	cout << "array1打印输出:" << endl;
	printIntArray(array1);
	cout << "array1的大小:" << array1.getSize() << endl;
	cout << "array1的容量:" << array1.getCapacity() << endl;

	cout << "--------------------------" << endl;

	MyArray<int> array2(array1);
	array2.Pop_back();
	cout << "array2打印输出:" << endl;
	printIntArray(array2);
	cout << "array2的大小:" << array2.getSize() << endl;
	cout << "array2的容量:" << array2.getCapacity() << endl;
}

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

void printPersonArray(MyArray<Person>& personArr)
{
    
    
	for (int i = 0; i < personArr.getSize(); i++) {
    
    
		cout << "姓名:" << personArr[i].m_Name << " 年龄: " << personArr[i].m_Age << endl;
	}

}

void test02()
{
    
    
	//创建数组
	MyArray<Person> pArray(10);
	Person p1("孙悟空", 30);
	Person p2("韩信", 20);
	Person p3("妲己", 18);
	Person p4("王昭君", 15);
	Person p5("赵云", 24);

	//插入数据
	pArray.Push_back(p1);
	pArray.Push_back(p2);
	pArray.Push_back(p3);
	pArray.Push_back(p4);
	pArray.Push_back(p5);

	printPersonArray(pArray);

	cout << "pArray的大小:" << pArray.getSize() << endl;
	cout << "pArray的容量:" << pArray.getCapacity() << endl;

}

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

Summarize:

Able to use the knowledge points learned to implement general arrays

2 First introduction to STL

2.1 The birth of STL

  • The software community has long wanted to build something reusable

  • The object-oriented and generic programming ideas of C++ are designed to improve reusability

  • In most cases, there is no set standard for data structures and algorithms, resulting in a large amount of duplication of work.

  • In order to establish a set of standards for data structures and algorithms , STL was born

    1.
    Encapsulation : abstract some things with similar attributes and behaviors as a whole to realize these things and things. This improves reusability
    2. Inheritance : Subclasses inherit from parent classes. Get all the properties and behaviors in the parent class. No need to restate it. This also improves code reuse.
    3. Polymorphism : A function name has multiple interfaces. They are also the same name, because the objects are different. The parent class pointer points to the subclass object. If the object is created differently, calling the same interface will produce different forms. This also improves reusability.

2.2 Basic concepts of STL

  • STL (Standard Template Library, standard template library )
  • STL is broadly divided into: container (container) algorithm (algorithm) iterator (iterator)
  • Containers and algorithms are seamlessly connected through iterators .
  • Almost all code in STL uses template classes or template functions

2.3 Six major components of STL

STL is roughly divided into six major components, namely:Containers, algorithms, iterators, functors, adapters (adapters), spatial configurators

  1. Container: Various data structures, such as vector, list, deque, set, map, etc., are used to store data.
  2. Algorithms: various commonly used algorithms, such as sort, find, copy, for_each, etc.
  3. Iterator: acts as the glue between the container and the algorithm.
  4. Functor: Behaves like a function and can be used as a strategy for an algorithm.
  5. Adapter: Something used to decorate a container or functor or iterator interface.
  6. Space configurator: Responsible for space configuration and management.

2.4 Containers, algorithms, and iterators in STL

Container : a place to store things

STL containers implement some of the most widely used data structures.
Commonly used data structures: arrays, linked lists, trees, stacks, queues, sets, mapping tables, etc. These
containers are divided into two types : sequential containers and associative containers :

  • tiered container: Emphasizes the ordering of values, and each element in the sequence container has a fixed position. That is, the insertion order is his order
    • For example: the insertion order is 13542, and the container order is also 13542
  • ​Associative containers:Binary tree structure, there is no strict physical order relationship between elements. That is, sorting is performed when inserting
    • For example: the insertion order is 13542 and the container order is 12345

Algorithm : The solution to a problem is also
a limited number of steps to solve logical or mathematical problems. This subject is called Algorithms.
Algorithms are divided into: qualitative change algorithms and non-qualitative change algorithms .

  • qualitative change algorithm: refers to the content of the elements in the interval that will be changed during the operation. For example, copy, replace, delete, etc.

  • non-qualitative algorithm: means that the content of elements within the interval will not be changed during the operation, such as searching, counting, traversing, finding extreme values, etc.

Iterator : The glue between the container and the algorithm, that is, the algorithm must use the iterator to access the elements in the container.
Provides a way to sequentially access the elements contained in a container without exposing the container's internal representation.

Each container has its own iterator

The use of iterators is very similar to pointers. In the beginner stage, we can first understand that iterators are pointers.

Iterator types :

type Function Support calculation
input iterator Read-only access to data Read-only, supports ++, ==,! =
output iterator Write-only access to data Write only, supports ++
forward iterator Read and write operations, and can advance the iterator Reading and writing, supports ++, ==,! =
bidirectional iterator Read and write operations, and can operate forward and backward Read and write, supports ++, –,
Random access iterator Read and write operations, you can access any data in a jumping manner, the most powerful iterator Read and write, supports ++, –, [n], -n, <, <=, >, >=

Commonly used types of iterators in containers are bidirectional iterators and random access iterators.

2.5 First introduction to container algorithm iterators

After understanding the concepts of containers, algorithms, and iterators in STL, we use code to feel the charm of STL

The most commonly used container in STL is Vector, which can be understood as an array . Below we will learn how to insert data into this container and traverse this container.

2.5.1 vector stores built-in data types

container:vector

algorithm:for_each

Iterator:vector<int>::iterator

Insert image description here

Example:

#include <vector>
#include <algorithm>

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

void test01() {
    
    

	//创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型
	vector<int> v;
	//向容器中放数据
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	//每一个容器都有自己的迭代器,迭代器是用来遍历容器中的元素,拿到容器中的元素
	//v.begin()返回迭代器,这个迭代器指向容器中第一个数据
	//v.end()返回迭代器,这个迭代器指向容器元素的最后一个元素的下一个位置
	//vector<int>::iterator 拿到vector<int>这种容器类型下的迭代器

	vector<int>::iterator pBegin = v.begin();
	vector<int>::iterator pEnd = v.end();

	//第一种遍历方式:
	while (pBegin != pEnd) {
    
    
		cout << *pBegin << endl; //解引用的方式,取出里面的数据
		pBegin++;
	}

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

	//第三种遍历方式:
	//使用STL提供标准遍历算法  头文件 algorithm
	for_each(v.begin(), v.end(), MyPrint);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

2.5.2 Vector stores custom data types

Learning goal: Store custom data types in vector and print output

Example:

#include <vector>
#include <string>

//自定义数据类型
class Person {
    
    
public:
	Person(string name, int age) {
    
    
		mName = name;
		mAge = age;
	}
public:
	string mName;
	int mAge;
};
//存放对象
void test01() {
    
    

	vector<Person> v;

	//创建数据
	Person p1("a", 1);
	Person p2("b", 2);
	Person p3("c", 3);

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

	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		cout << "Name:" << (*it).mName << " Age:" << (*it).mAge << endl;
	 	//cout << "Name:" << it->mName << " Age:" << it->mAge << endl;
	}
}


//存放自定义数据类型对象 指针
void test02() {
    
    

	vector<Person*> v;

	//创建数据
	Person p1("aa", 1);
	Person p2("bb", 2);
	Person p3("cc", 3);

	v.push_back(&p1); //把地址保存 故加上&取址符号
	v.push_back(&p2);
	v.push_back(&p3);

	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
    
    
		Person * p = (*it);
		cout << "Name:" << p->mName << " Age:" << (*it)->mAge << endl;
	}
}


int main() {
    
    

	test01();
    
	test02();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

2.5.3 Vector container nested container

Learning goal: Nested containers within containers, we traverse and output all data

Example:

#include <vector>

//容器嵌套容器
void test01() {
    
    

	vector< vector<int> >  v;

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

	//将小容器元素插入到大容器vector v中
	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<int>类型的容器
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) {
    
    
			cout << *vit << " ";
		}
		cout << endl;
	}

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

3 STL-common containers

3.1 string container

3.1.1 Basic concepts of string

Nature:

  • string is a C++ style string, and string is essentially a class

The difference between string and char *:

  • char * is a pointer
  • String is a class , which encapsulates char* inside the class. It manages this string as a char* type container .

Features:

The string class encapsulates many member methods internally

For example: find, copy, delete, replace, insert

String manages the memory allocated by char*. You don’t have to worry about copying out of bounds and value out of bounds. The responsibility is handled internally by the class.

3.1.2 string constructor

Constructor prototype:

  • string();//Create an empty string. For example: string str;
    string(const char* s);//Initialize with string s.
  • string(const string& str);//Use one string object to initialize another string object, that is, copy construction
  • string(int n, char c);//Initialize with n characters c

Example:

#include <string>
//string构造
void test01()
{
    
    
	string s1; //默认构造。 创建空字符串,调用无参构造函数
	cout << "str1 = " << s1 << endl;

	const char* str = "hello world";
	string s2(str); //把c_string转换成了string
	cout << "str2 = " << s2 << endl;

	string s3(s2); //调用拷贝构造函数
	cout << "str3 = " << s3 << endl;

	string s4(10, 'a'); //创建10个a
	cout << "str4 = " << s4 << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The various construction methods of string are not comparable, just use them flexibly.

3.1.3 string assignment operation

Function description:

  • Assign a value to a string string

Assigned function prototype:

  • string& operator=(const char* s);//char* type string is assigned to the current string
  • string& operator=(const string &s);//Assign string s to the current string
  • string& operator=(char c);//Assign characters to the current string
  • string& assign(const char *s);//Assign string s to the current string
  • string& assign(const char *s, int n);//Assign the first n characters of string s to the current string
  • string& assign(const string &s);//Assign string s to the current string
  • string& assign(int n, char c);//Assign n characters c to the current string

Example:

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

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

	string str3;
	str3 = 'a';
	cout << "str3 = " << str3 << endl;

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

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

	string str6;
	str6.assign(str5);
	cout << "str6 = " << str6 << endl;

	string str7;
	str7.assign(5, 'x');
	cout << "str7 = " << str7 << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

There are many ways to assign string values, and operator=this method is more practical.

3.1.4 string string concatenation

Function description:

  • Implement concatenating strings at the end of strings

Function prototype:

  • string& operator+=(const char* str);//Overload the += operator
  • string& operator+=(const char c);//Overload the += operator
  • string& operator+=(const string& str);//Overload the += operator
  • string& append(const char *s); //Concatenate string s to the end of the current string
  • string& append(const char *s, int n);//Concatenate the first n characters of string s to the end of the current string
  • string& append(const string &s); //同operator+=(const string& str)
  • string& append(const string &s, int pos, int n);//The n characters starting from pos in string s are connected to the end of the string

Example:

//字符串拼接
void test01()
{
    
    
	string str1 = "我";
	str1 += "爱玩游戏";
	cout << "str1 = " << str1 << endl;
	
	str1 += ':';
	cout << "str1 = " << str1 << endl;

	string str2 = "LOL DNF";
	str1 += str2;
	cout << "str1 = " << str1 << endl;

	string str3 = "I";
	str3.append(" love ");
	str3.append("game abcde", 4);
	//str3.append(str2);
	str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
	cout << "str3 = " << str3 << endl;
}
int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: There are many overloaded versions of string concatenation. Just remember a few at the beginning stage.

3.1.5 string search and replace

Function description:

  • Find: Find whether the specified string exists
  • Replace: Replace the string at the specified position

Function prototype:

  • int find(const string& str, int pos = 0) const;//Find the first occurrence of str, starting from pos
  • int find(const char* s, int pos = 0) const; //Find the first occurrence of s, starting from pos
  • int find(const char* s, int pos, int n) const; //Find the first position of the first n characters of s from the pos position
  • int find(const char c, int pos = 0) const; //Find the first occurrence of character c
  • int rfind(const string& str, int pos = npos) const;//Find the last position of str, starting from pos
  • int rfind(const char* s, int pos = npos) const;//Find the last occurrence of s, starting from pos
  • int rfind(const char* s, int pos, int n) const;//Find the last position of the first n characters of s from pos
  • int rfind(const char c, int pos = 0) const; //Find the last occurrence of character c
  • string& replace(int pos, int n, const string& str); //Replace n characters starting from pos with string str
  • string& replace(int pos, int n,const char* s); //Replace n characters starting from pos with string s

Example:

//查找和替换
void test01()
{
    
    
	//查找
	string str1 = "abcdefgde";

	int pos = str1.find("de");

	if (pos == -1)
	{
    
    
		cout << "未找到" << endl;
	}
	else
	{
    
    
		cout << "pos = " << pos << endl;
	}
	

	pos = str1.rfind("de");

	cout << "pos = " << pos << endl;

}

void test02()
{
    
    
	//替换
	string str1 = "abcdefgde";
	str1.replace(1, 3, "1111");

	cout << "str1 = " << str1 << endl;
}

int main() {
    
    

	//test01();
	//test02();

	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summarize:

  • find searches from left to back, rfind searches from right to left
  • After find finds the string, it returns the position of the first character found. If it cannot find it, it returns -1.
  • When replacing, you need to specify the starting position, how many characters, and what kind of string to replace.

3.1.6 string string comparison

Function description:

  • Comparison between strings

How to compare:

  • String comparison is based on the ASCII code of characters.

= return 0

> Return 1

< return -1

Function prototype:

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

Example:

//字符串比较
void test01()
{
    
    

	string s1 = "hello";
	string s2 = "aello";

	int ret = s1.compare(s2);

	if (ret == 0) {
    
    
		cout << "s1 等于 s2" << endl;
	}
	else if (ret > 0)
	{
    
    
		cout << "s1 大于 s2" << endl;
	}
	else
	{
    
    
		cout << "s1 小于 s2" << endl;
	}

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary : String comparison is mainly used to compare whether two strings are equal. It is not very meaningful to determine which one is bigger and which one is smaller.

3.1.7 string character access

There are two ways to access a single character in string

  • char& operator[](int n); //Get characters through [] method
  • char& at(int n); //Get characters through at method

Example:

void test01()
{
    
    
	string str = "hello world";
	
	//1、通过[]访问单个字符
	for (int i = 0; i < str.size(); i++)
	{
    
    
		cout << str[i] << " ";
	}
	cout << endl;

	//2、通过at方式访问单个字符
	for (int i = 0; i < str.size(); i++)
	{
    
    
		cout << str.at(i) << " ";
	}
	cout << endl;


	//字符修改
	str[0] = 'x';
	str.at(1) = 'x';
	cout << str << endl;
	
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: There are two ways to access a single character in a string string, using [ ] or at

3.1.8 string insertion and deletion

Function description:

  • Insert and delete characters into string strings

Function prototype:

  • string& insert(int pos, const char* s); //insert string
  • string& insert(int pos, const string& str); //insert string
  • string& insert(int pos, int n, char c);//Insert n characters c at the specified position
  • string& erase(int pos, int n = npos);//Delete n characters starting from Pos

Example:

//字符串插入和删除
void test01()
{
    
    
	string str = "hello";
	str.insert(1, "111");
	cout << str << endl;

	str.erase(1, 3);  //从1号位置开始3个字符
	cout << str << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary : The starting subscripts for insertion and deletion start from 0.

3.1.9 string substring

Function description:

  • Get the desired substring from a string

Function prototype:

  • string substr(int pos = 0, int n = npos) const;//Return a string consisting of n characters starting from pos

Example:

//子串
void test01()
{
    
    

	string str = "abcdefg";
	string subStr = str.substr(1, 3);
	cout << "subStr = " << subStr << endl;

	string email = "[email protected]";
	int pos = email.find("@"); 
	string username = email.substr(0, pos);
	cout << "username: " << username << endl;

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

**Summary:** Flexible use of the substring function can obtain effective information in actual development

3.2 vector container

3.2.1 Basic concepts of vector

Function:

  • The vector data structure is very similar to an array , also known as a single-ended array

The difference between vector and ordinary array:

  • The difference is that arrays are static spaces, while vectors can be expanded dynamically

Dynamic expansion:

  • Instead of connecting the new space to the original space, we find a larger memory space, and then copy the original data to the new space to release the original space.

Insert image description here

  • The iterator of the vector container is an iterator that supports random access

3.2.2 vector constructor

Function description:

  • Create vector container

Function prototype:

  • vector<T> v; //Adopt template implementation class implementation, default constructor
  • vector(v.begin(), v.end()); // Copy the elements in the range v [ begin(), end() ) to itself.
  • vector(n, elem);//The constructor copies n elems to itself.
  • vector(const vector &vec);//Copy constructor.

Example:

#include <vector>

void printVector(vector<int>& v) {
    
    

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

void test01()
{
    
    
	//1、默认构造 无参构造
	vector<int> v1; 
	//容器中添加数据
	for (int i = 0; i < 10; i++)
	{
    
    
		v1.push_back(i);
	}
	printVector(v1);
	
	//2、通过区间方式进行构造
	 //左闭右开  end指向最后一个元素的下一个位置
	 //vector容器中可以通过begin和end迭代器传入 把两个迭代器间的数值传入
	vector<int> v2(v1.begin(), v1.end());
	printVector(v2);

	//3、n个elem方式构造
	vector<int> v3(10, 100); //10个100
	printVector(v3);
	
	//拷贝构造
	vector<int> v4(v3);
	printVector(v4);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary : The various construction methods of vector are not comparable, just use them flexibly.

3.2.3 vector assignment operation

Function description:

  • Assign values ​​to the vector container

Function prototype:

  • vector& operator=(const vector &vec);//Overload the equal sign operator

  • assign(beg, end);//Copy and assign the data in the [beg, end) interval to itself.

  • assign(n, elem);//Assign n elem copies to itself.

Example:

#include <vector>

void printVector(vector<int>& v) {
    
    

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

//赋值操作
void test01()
{
    
    
	vector<int> v1; //无参构造
	for (int i = 0; i < 10; i++)
	{
    
    
		v1.push_back(i);
	}
	printVector(v1);
	
	//1、赋值 operator=
	vector<int>v2;
	v2 = v1;
	printVector(v2);

	//2、赋值 assign
	vector<int>v3;
	v3.assign(v1.begin(), v1.end());
	printVector(v3);

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The vector assignment method is relatively simple. You can use operator= or assign.

3.2.4 Vector capacity and size

Function description:

  • Capacity and size operations on vector containers

Function prototype:

  • empty(); //Determine whether the container is empty

  • capacity();//Container capacity

  • size();//Return the number of elements in the container

  • resize(int num);//Respecify the length of the container to num. If the container becomes longer, fill the new position with the default value.

    ​ //If the container becomes shorter, the elements at the end that exceed the length of the container are deleted.

  • resize(int num, elem);//Respecify the length of the container to num. If the container becomes longer, fill the new position with the elem value.

    ​ //If the container becomes shorter, the elements at the end that exceed the length of the container are deleted.

Example:

#include <vector>

void printVector(vector<int>& v) {
    
    

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

void test01()
{
    
    
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
    
    
		v1.push_back(i);
	}
	printVector(v1);
	
    //判断容器是否为空
	if (v1.empty())
	{
    
    
		cout << "v1为空" << endl;
	}
	else
	{
    
    
		cout << "v1不为空" << endl;
		cout << "v1的容量 = " << v1.capacity() << endl;
		cout << "v1的大小 = " << v1.size() << endl;
	}

	//resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充
	v1.resize(15,10);
	printVector(v1);

	//resize 重新指定大小 ,若指定的更小,超出部分元素被删除
	v1.resize(5);
	printVector(v1);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Determine whether it is empty - empty
  • Returns the number of elements — size
  • Returns the container capacity—capacity
  • Resize — resize

3.2.5 vector insertion and deletion

Function description:

  • Insert and delete vector containers

Function prototype:

  • push_back(ele);//Insert element ele at the end
  • pop_back();//Delete the last element
  • insert(const_iterator pos, ele);//The iterator points to position pos to insert element ele
  • insert(const_iterator pos, int count,ele);//The iterator points to position pos and inserts count elements ele
  • erase(const_iterator pos);//Delete the element pointed to by the iterator
  • erase(const_iterator start, const_iterator end);//Delete the elements between the iterator from start to end
  • clear();//Delete all elements in the container

Example:


#include <vector>

void printVector(vector<int>& v) {
    
    

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

//插入和删除
void test01()
{
    
    
	vector<int> v1;
	//尾插
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	printVector(v1);
	
	//尾删
	v1.pop_back();
	printVector(v1);
	
	//插入 提供一个迭代器进行插入  第一个参数是迭代器
	v1.insert(v1.begin(), 100);
	printVector(v1);

	v1.insert(v1.begin(), 2, 1000); //在头部插2个1000
	printVector(v1);

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

	//清空
	v1.erase(v1.begin(), v1.end());
	v1.clear();
	printVector(v1);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Tail insert — push_back
  • Tail delete—pop_back
  • Insert — insert (positional iterator)
  • Delete — erase (positional iterator)
  • clear — clear

3.2.6 Vector data access

Function description:

  • Access operations to data in vector

Function prototype:

  • at(int idx); //Return the data pointed to by index idx
  • operator[]; //Return the data pointed to by index idx
  • front(); //Return the first data element in the container
  • back();//Return the last data element in the container

Example:

#include <vector>

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

	//2、利用at方式访问元素
	for (int i = 0; i < v1.size(); i++)
	{
    
    
		cout << v1.at(i) << " ";
	}
	cout << endl;

	cout << "v1的第一个元素为: " << v1.front() << endl;
	cout << "v1的最后一个元素为: " << v1.back() << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • In addition to using iterators to obtain elements in the vector container, [ ] and at can also be used
  • front returns the first element of the container
  • back returns the last element of the container

3.2.7 vector interchange container

Function description:

  • Implement exchange of elements in two containers

Function prototype:

  • swap(vec);// Swap vec with its own elements

Example:

#include <vector>

void printVector(vector<int>& v) {
    
    

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

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

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

	//互换容器
	cout << "互换后" << endl;
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}

//实际用途
//巧用swap可以收缩内存
void test02()
{
    
    
	vector<int> v;
	for (int i = 0; i < 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;

	//收缩内存
	vector<int>(v).swap(v); //匿名对象

	cout << "v的容量为:" << v.capacity() << endl;
	cout << "v的大小为:" << v.size() << endl;
}

int main() {
    
    

	test01();

	test02();

	system("pause");

	return 0;
}

Insert image description here

Insert image description here
Insert image description here
Insert image description here
Insert image description here

Summary: swap can make two containers interchangeable and can achieve a practical memory shrinking effect.

3.2.8 vector reserved space

Function description:

  • Reduce the number of expansions of vector when dynamically expanding its capacity

Function prototype:

  • reserve(int len);//The container reserves a length of len elements, the reserved position is not initialized, and the elements are inaccessible . It just allocates memory. The data in the memory is not initialized, so it cannot be accessed.

Example:

#include <vector>

void test01()
{
    
    
	vector<int> v;

	//会节省动态开辟操作,利用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();
    
	system("pause");

	return 0;
}

Insert image description here
Insert image description here

Summary: If the amount of data is large, you can use reserve to reserve space at the beginning.

3.3 deque container

3.3.1 Basic concepts of deque container

Function:

  • Double-ended array, you can perform insertion and deletion operations on the head end

The difference between deque and vector:

  • Vector has low efficiency for inserting and deleting headers. The larger the amount of data, the lower the efficiency.
  • Relatively speaking, deque is faster than vector in inserting and deleting headers.
  • The speed of vector accessing elements is faster than that of deque , which is related to the internal implementation of the two.
    • When accessing the next one, you need to access the data in the next buffer through the address.

Insert image description here

The internal working principle of deque:

  • There is a central controller inside deque that maintains the contents of each buffer and stores real data in the buffer.
  • The central controller maintains the address of each buffer, making it look like a continuous memory space when using deque.
    Insert image description here
    Insert image description here
  • The iterator of the deque container also supports random access .

3.3.2 deque constructor

Function description:

  • deque container construction

Function prototype:

  • deque<T>deqT; //Default construction form
  • deque(beg, end);//The constructor copies the elements in the range [beg, end) to itself.
  • deque(n, elem);//The constructor copies n elems to itself.
  • deque(const deque &deq);//copy constructor

Example:

#include <deque>

void printDeque(const deque<int>& d) //加上const
{
    
    
	//此时迭代器iterator,要修改成只读的迭代器const_iterator
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		//*it=100; //容器里中的数据不可以修改了
		cout << *it << " ";
	}
	cout << endl;
}
//deque构造
void test01() {
    
    

	deque<int> d1; //无参构造函数
	for (int i = 0; i < 10; i++)
	{
    
    
		d1.push_back(i);
	}
	printDeque(d1);
	
	deque<int> d2(d1.begin(),d1.end());
	printDeque(d2);

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

	deque<int>d4 = d3;
	printDeque(d4);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary : The construction methods of deque containers and vector containers are almost the same, and they can be used flexibly.

3.3.3 deque assignment operation

Function description:

  • Assign values ​​to the deque container

Function prototype:

  • deque& operator=(const deque &deq); //Overload the equal sign operator

  • assign(beg, end);//Copy and assign the data in the [beg, end) interval to itself.

  • assign(n, elem);//Assign n elem copies to itself.

Example:

#include <deque>

void printDeque(const deque<int>& d) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}
//赋值操作
void test01()
{
    
    
	deque<int> d1;
	for (int i = 0; i < 10; i++)
	{
    
    
		d1.push_back(i);
	}
	printDeque(d1);

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

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

	//n个elem赋值
	deque<int>d4;
	d4.assign(10, 100);
	printDeque(d4);

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The deque assignment operation is also the same as vector and needs to be mastered proficiently.

3.3.4 deque size operation

Function description:

  • Operate the size of the deque container

Function prototype:

  • deque.empty();//Determine whether the container is empty

  • deque.size();//Return the number of elements in the container

  • deque.resize(num);//Respecify the length of the container to num. If the container becomes longer, fill the new position with the default value.

    ​ //If the container becomes shorter, the elements at the end that exceed the length of the container are deleted.

  • deque.resize(num, elem);//Respecify the length of the container to num. If the container becomes longer, fill the new position with the elem value.

    ​ //If the container becomes shorter, the elements at the end that exceed the length of the container are deleted.

Example:

#include <deque>

void printDeque(const deque<int>& d) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}

//大小操作
void test01()
{
    
    
	deque<int> d1;
	for (int i = 0; i < 10; i++)
	{
    
    
		d1.push_back(i);
	}
	printDeque(d1);

	//判断容器是否为空
	if (d1.empty()) {
    
    
		cout << "d1为空!" << endl;
	}
	else {
    
    
		cout << "d1不为空!" << endl;
		//统计大小
		cout << "d1的大小为:" << d1.size() << endl;
	}

	//重新指定大小
	d1.resize(15, 1);
	printDeque(d1);

	//如果容器变短,则末尾超出容器长度的元素被删除
	d1.resize(5);
	printDeque(d1);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • deque has no concept of capacity
    • deque can open up new buffers infinitely. The central controller only needs to add an address to maintain those small segments of space.
    • The vector memory space is continuous, but the deque memory space is not continuous.
    • Vector has only one space, and deque is composed of multiple small spaces. New spaces will be created only when the small spaces are full, and empty spaces will be deleted.
    • Deque is a wirelessly extended two-way queue. The purpose is to solve the problem of vector header data storage and deletion. This is a common problem of arrays because it requires a shift operation. It just borrows the concept of fragmented storage.
  • Determine whether it is empty - empty
  • Returns the number of elements — size
  • Respecify the number—resize

3.3.5 deque insertion and deletion

Function description:

  • Insert and delete data into deque container

Function prototype:

Insertion operation at both ends:

  • push_back(elem);//Add a data at the end of the container
  • push_front(elem);//Insert a data into the head of the container
  • pop_back();//Delete the last data in the container
  • pop_front();//Delete the first data of the container

Specify location operation:

  • insert(pos,elem);//Insert a copy of the elem element at the pos position and return the position of the new data.

  • insert(pos,n,elem);//Insert n elem data at pos position, no return value.

  • insert(pos,beg,end);//Insert the data in the interval [beg, end) at the pos position, with no return value.

  • clear();//Clear all data in the container

  • erase(beg,end);//Delete the data in the [beg, end) interval and return the position of the next data.

  • erase(pos);//Delete the data at pos position and return the position of the next data.

Example:

#include <deque>

void printDeque(const deque<int>& d) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}

//两端操作
void test01()
{
    
    
	deque<int> d;
	
	//尾插
	d.push_back(10);
	d.push_back(20);
	
	//头插
	d.push_front(100);
	d.push_front(200);

	printDeque(d);

	//尾删
	d.pop_back();
	//头删
	d.pop_front();
	
	printDeque(d);
}

//插入
void test02()
{
    
    
	deque<int> d1;
	d1.push_back(10);
	d1.push_back(20);
	d1.push_front(100);
	d1.push_front(200);

	// 200 100 10 20
	printDeque(d1);
	
	//insert插入
	// 1000 200 100 10 20
	d.insert(d1.begin(), 1000);
	printDeque(d1);

	// 10000 10000 1000 200 100 10 20
	d1.insert(d1.begin(), 2,10000);
	printDeque(d1);

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

	// 1 2 3 10000 10000 1000 200 100 10 20
	d1.insert(d1.begin(), d2.begin(), d2.end());
	printDeque(d1);

}

//删除
void test03()
{
    
    
	deque<int> d3;
	d3.push_back(10);
	d3.push_back(20);
	d3.push_front(100);
	d3.push_front(200);
	
	// 200 100 10 20
	printDeque(d3);

	deque<int>::iterator it = d3.begin();
	it++;
	d3.erase(it);
	// 200 10 20
	printDeque(d3);

	//清空
	d3.erase(d3.begin(), d3.end());
	d3.clear();
	printDeque(d3);
}

int main() {
    
    

	//test01();

	//test02();

    test03();
    
	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • The positions provided for insertion and deletion are iterators!
  • Tail insert — push_back
  • Tail delete—pop_back
  • Head plug — push_front
  • Header deletion — pop_front

3.3.6 deque data access

Function description:

  • Access operations to data in deque

Function prototype:

  • at(int idx); //Return the data pointed to by index idx
  • operator[]; //Return the data pointed to by index idx
  • front(); //Return the first data element in the container
  • back();//Return the last data element in the container

Example:

#include <deque>

void printDeque(const deque<int>& d) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}

//数据存取
void test01()
{
    
    

	deque<int> d;
	d.push_back(10);
	d.push_back(20);
	d.push_front(100);
	d.push_front(200);

	for (int i = 0; i < d.size(); i++) {
    
    
		cout << d[i] << " ";
	}
	cout << endl;


	for (int i = 0; i < d.size(); i++) {
    
    
		cout << d.at(i) << " ";
	}
	cout << endl;

	cout << "front:" << d.front() << endl;

	cout << "back:" << d.back() << endl;

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • In addition to using iterators to obtain elements in the deque container, [ ] and at can also be used
  • front returns the first element of the container
  • back returns the last element of the container

3.3.7 deque sorting

Function description:

  • Use algorithms to sort deque containers

algorithm:

  • sort(iterator beg, iterator end)//Sort the elements in the beg and end intervals
    • For containers that support random access iterators, you can use the sort algorithm to sort them directly.
    • Vector containers can also be sorted by sort

Example:

#include <deque>
#include <algorithm>

void printDeque(const deque<int>& d) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		cout << *it << " ";

	}
	cout << endl;
}

void test01()
{
    
    

	deque<int> d;
	d.push_back(10);
	d.push_back(20);
	d.push_front(100);
	d.push_front(200);

	printDeque(d);
	//排序默认是从小到大,升序
	sort(d.begin(), d.end());
	printDeque(d);

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The sort algorithm is very practical. Just include the header file algorithm when using it.

3.4 Case - Judges’ Scoring

3.4.1 Case description

There are 5 contestants: contestants ABCDE, 10 judges will score each contestant separately, remove the highest score, remove the lowest score among the judges, and calculate the average score.

3.4.2 Implementation steps

  1. Create five players and put them in vector
  2. Traverse the vector container, take out each player, execute the for loop, and save the 10 judges' scores into the deque container.
  3. The sort algorithm sorts the scores in the deque container and removes the highest and lowest scores.
  4. The deque container is traversed once and the total score is accumulated.
  5. get average score

Sample code:

//选手类
class Person
{
    
    
public:
	Person(string name, int score)
	{
    
    
		this->m_Name = name;
		this->m_Score = score;
	}

	string m_Name; //姓名
	int m_Score;  //平均分
};

//1、创建5名选手
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);
	}
}

//2、给5名选手打分
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 【rand() % 41】表示0~40
			d.push_back(score);
		}

		//cout << "选手: " << it->m_Name << " 打分: " << endl;
		//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;
	}

}

//3、显示最后得分
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 main() {
    
    

	//随机数种子,不加这个的话,每次的随机评委打分不会更改
	srand((unsigned int)time(NULL));

	//1、创建5名选手
	vector<Person>v;  //存放选手容器
	createPerson(v);

	//测试
	//for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	//{
    
    
	//	cout << "姓名: " << (*it).m_Name << " 分数: " << (*it).m_Score << endl;
	//}

	//2、给5名选手打分
	setScore(v);

	//3、显示最后得分
	showScore(v);

	system("pause");

	return 0;
}

Insert image description here

Summary: Selecting different container operation data can improve the efficiency of the code

3.5 stack container

3.5.1 Basic concepts of stack

Concept: stack is aFirst in, last out(First In Last Out, FILO) data structure, it has only one outlet

Insert image description here
Insert image description here

in stackOnly the top elements can be used by the outside world, so the stackTraversal behavior is not allowed

Entering data into the stack is called - pushing onto the stack push

Popping data from the stack is called popping pop

3.5.2 stack common interfaces

Function description: Commonly used external interfaces of stack containers

Constructor:

  • stack<T> stk;//stack is implemented using a template class, the default construction form of the stack object
  • stack(const stack &stk);//copy constructor

Assignment operation:

  • stack& operator=(const stack &stk);//Overload the equal sign operator

Data access:

  • push(elem);//Add element to top of stack
  • pop();//Remove the first element from the top of the stack
  • top(); //Return the top element of the stack

Big and small operations:

  • empty();//Determine whether the stack is empty
  • size(); //return stack size

Example:

#include <stack>

//栈容器常用接口
void test01()
{
    
    
	//创建栈容器 栈容器必须符合先进后出
	stack<int> s;

	//向栈中添加元素,叫做 压栈 入栈
	s.push(10);
	s.push(20);
	s.push(30);

	//只要栈不为空,查看栈顶,并且执行出栈操作
	while (!s.empty()) {
    
    
		//输出栈顶元素
		cout << "栈顶元素为: " << s.top() << endl;
		//弹出栈顶元素
		s.pop();
	}
	cout << "栈的大小为:" << s.size() << endl;

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Push to the stack — push
  • pop — pop
  • Return to the top of the stack — top
  • Determine whether the stack is empty - empty
  • Return stack size — size

3.6 queue container

3.6.1 Basic concepts of queue

Concept: Queue is afirst in first out(First In First Out, FIFO) data structure, which has two exits

Insert image description here

  • Queue container allowsAdd elements from one end,fromRemove element on the other side

  • in queueOnly the head and tail of the team can be used by the outside world,thereforeThe queue does not allow traversal behavior

  • Entering data into the queue is called enqueuing push

  • Dequeuing data from the queue is called dequeuing pop

Queues in life:
Insert image description here

3.6.2 queue common interfaces

Function description: Commonly used external interfaces of stack containers

Constructor:

  • queue<T> que;//queue is implemented using a template class, the default construction form of the queue object
  • queue(const queue &que);//copy constructor

Assignment operation:

  • queue& operator=(const queue &que);//Overload the equal sign operator

Data access:

  • push(elem);//Add elements to the end of the queue
  • pop();//Remove the first element from the head of the queue
  • back();//Return the last element
  • front(); //Return the first element

Big and small operations:

  • empty();//Determine whether the stack is empty
  • size(); //return stack size

Example:

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

	string m_Name;
	int m_Age;
};

void test01() {
    
    

	//创建队列
	queue<Person> q;

	//准备数据
	Person p1("isak", 11);
	Person p2("even", 22);
	Person p3("eva", 33);

	//向队列中添加元素  入队操作
	q.push(p1);
	q.push(p2);
	q.push(p3);

	//队列不提供迭代器,更不支持随机访问	
	while (!q.empty()) {
    
    
		//输出队头元素
		cout << "队头元素-- 姓名: " << q.front().m_Name 
              << " 年龄: "<< q.front().m_Age << endl;
        //输出队尾元素
		cout << "队尾元素-- 姓名: " << q.back().m_Name  
              << " 年龄: " << q.back().m_Age << endl;
        
		cout << endl;
		//弹出队头元素
		q.pop();
	}

	cout << "队列大小为:" << q.size() << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Enqueue — push
  • Dequeue — pop
  • Returns the head element of the queue - front
  • Return the last element of the queue - back
  • Determine whether the queue is empty - empty
  • Return queue size — size

3.7 list container

3.7.1 Basic concepts of list

  • Function : chain storage of data

  • A linked list (list) is a non-continuous storage structure on a physical storage unit. The logical order of data elements is implemented through pointer links in the linked list.

  • The composition of a linked list: a linked list consists of a series of nodes

  • The composition of nodes: one isStore data elementsdata field , the other isStore the next node addresspointer field

  • The linked list in STL is a two-way circular linked list

Insert image description here
Insert image description here

  • Since the storage method of the linked list is not a continuous memory space , the iterator in the linked list only supports forward and backward movements and is a bidirectional iterator.

Advantages of list:

  • Dynamic storage allocation is used to avoid memory waste and overflow.
  • It is very convenient to perform insertion and deletion operations in a linked list. You only need to modify the pointer without moving a large number of elements.

Disadvantages of list:

  • Linked lists are flexible, but consume a lot of space (pointer field) and time (traversal).

List has an important property. Neither insertion nor deletion operations will cause the original list iterator to become invalid. This is not true for vector.

Summary: List and vector are the two most commonly used containers in STL , each with its own advantages and disadvantages.

3.7.2 list constructor

Function description:

  • Create a list container

Function prototype:

  • list<T> lst;//The list is implemented using a template class, and the default construction form of the object is:
  • list(beg,end);//The constructor copies the elements in the range [beg, end) to itself.
  • list(n,elem);//The constructor copies n elems to itself.
  • list(const list &lst);//Copy constructor.

Example:

#include <list>

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

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

	printList(L1);

	list<int>L2(L1.begin(),L1.end());
	printList(L2);

	list<int>L3(L2);
	printList(L3);

	list<int>L4(10, 1000);
	printList(L4);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The list construction method is the same as that of several other common STL containers, and you only need to be proficient in it.

3.7.3 list assignment and exchange

Function description:

  • Assign values ​​to list containers and exchange list containers

Function prototype:

  • assign(beg, end);//Copy and assign the data in the [beg, end) interval to itself.
  • assign(n, elem);//Assign n elem copies to itself.
  • list& operator=(const list &lst);//Overload the equal sign operator
  • swap(lst);//Exchange lst with its own elements.

Example:

#include <list>

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

//赋值和交换
void test01()
{
    
    
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);

	//赋值 operator=
	list<int>L2;
	L2 = L1;
	printList(L2);

	list<int>L3;
	L3.assign(L2.begin(), L2.end());
	printList(L3);

	list<int>L4;
	L4.assign(10, 100);
	printList(L4);

}

//交换
void test02()
{
    
    

	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

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

	cout << "交换前: " << endl;
	printList(L1);
	printList(L2);

	cout << endl;

	L1.swap(L2);

	cout << "交换后: " << endl;
	printList(L1);
	printList(L2);

}

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

Insert image description hereInsert image description here

Summary: List assignment and exchange operations can be used flexibly

3.7.4 List size operations

Function description:

  • Operate the size of the list container

Function prototype:

  • size(); //Return the number of elements in the container

  • empty(); //Determine whether the container is empty

  • resize(num);//Respecify the length of the container to num. If the container becomes longer, fill the new position with the default value.

    ​ //If the container becomes shorter, the elements at the end that exceed the length of the container are deleted.

  • resize(num, elem); //Respecify the length of the container to num. If the container becomes longer, fill the new position with the elem value.

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

Example:

#include <list>

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

//大小操作
void test01()
{
    
    
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

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

	//重新指定大小
	L1.resize(10);
	printList(L1);

	L1.resize(2);
	printList(L1);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Determine whether it is empty - empty
  • Returns the number of elements — size
  • Respecify the number—resize

3.7.5 list insertion and deletion

Function description:

  • Insert and delete data into list container

Function prototype:

  • push_back(elem);//Add an element to the end of the container
  • pop_back();//Delete the last element in the container
  • push_front(elem);//Insert an element at the beginning of the container
  • pop_front();//Remove the first element from the beginning of the container
  • insert(pos,elem);//Insert a copy of the elem element at the pos position and return the position of the new data.
  • insert(pos,n,elem);//Insert n elem data at pos position, no return value.
  • insert(pos,beg,end);//Insert the data in [beg,end) interval at pos position, no return value.
  • clear();//Remove all data from the container
  • erase(beg,end);//Delete the data in [beg,end) interval and return the position of the next data.
  • erase(pos);//Delete the data at pos position and return the position of the next data.
  • remove(elem);//Delete all elements in the container that match the elem value.

Example:

#include <list>

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

//插入和删除
void test01()
{
    
    
	list<int> L;
	//尾插
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	//头插
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);

	// 300 200 100 10 20 30
	printList(L);

	//尾删
	L.pop_back();
	// 300 200 100 10 20 
	printList(L);

	//头删
	L.pop_front();
	// 200 100 10 20 
	printList(L);

	//插入
	list<int>::iterator it = L.begin();
	L.insert(++it, 1000);
	// 200 1000 100 10 20 
	printList(L);

	//删除
	it = L.begin();
	L.erase(++it);
	// 200 100 10 20 
	printList(L);

	//移除
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);
	// 200 100 10 20 10000 10000 10000
	printList(L);
	L.remove(10000);
	// 200 100 10 20 
	printList(L);
    
    //清空
	L.clear();
	printList(L);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Tail insert — push_back
  • Tail delete—pop_back
  • Head plug — push_front
  • Header deletion — pop_front
  • insert — insert
  • Delete—erase
  • Remove—remove
  • clear — clear

3.7.6 list data access

Function description:

  • Access data in the list container

Function prototype:

  • front();//Return the first element.
  • back();//Return the last element.

Example:

#include <list>

//数据存取
void test01()
{
    
    
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);

	
	//cout << L1.at(0) << endl;//错误 不支持at访问数据
	//cout << L1[0] << endl; //错误  不支持[]方式访问数据
	//原因是list本质是链表,不是连续线性空间存储数据,迭代器也是不支持随机访问的
	
	cout << "第一个元素为: " << L1.front() << endl;
	cout << "最后一个元素为: " << L1.back() << endl;

	//list容器的迭代器是双向迭代器,不支持随机访问
	list<int>::iterator it = L1.begin();
	it++; //支持,双向迭代器只支持++和--操作
	cout << "输出迭代器it++值:" << *it << endl;
	//it = it + 1;//错误,不支持随机访问,即使是+1
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Data in the list container cannot be accessed through [] or at.
  • Returns the first element — front
  • Return the last element — back

3.7.7 List reversal and sorting

Function description:

  • Reverse the elements in the container and sort the data in the container

Function prototype:

  • reverse();//reverse linked list
  • sort();//Sort the linked list

Example:

void printList(const list<int>& L) {
    
    

	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

bool myCompare(int val1 , int val2)
{
    
    
	//因为是int类型的,所以给两个int数据
	//降序 就让第一个数 > 第二个数	
	//返回真或假
	//可以结合冒泡排序进行理解,相当于对比两个相邻的数,然后交换(true)和不交换(false)由自己定夺
	return val1 > val2;
}

//反转和排序
void test01()
{
    
    
	list<int> L;
	L.push_back(90);
	L.push_back(30);
	L.push_back(20);
	L.push_back(70);
	printList(L);

	//反转容器的元素
	L.reverse();
	printList(L);

	//排序
	//所有不支持随机访问迭代器的容器,不可以用标准算法
	//sort(L.begin(),L.end());
	//不支持随机访问迭代器的容器,内部会提供对应一些算法
	L.sort(); //默认的排序规则 从小到大 升序
	printList(L);

	L.sort(myCompare); //指定规则,从大到小 降序
	printList(L);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • reverse—reverse
  • Sorting — sort (member function)

3.7.8 Sorting cases

Case description: Sort the Person custom data type. The attributes in Person include name, age, and height.

Sorting rules: ascending order by age, descending order by height if age is the same

Example:

#include <list>
#include <string>
class Person {
    
    
public:
	Person(string name, int age , int height) {
    
    
		m_Name = name;
		m_Age = age;
		m_Height = height;
	}

public:
	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 test01() {
    
    

	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;
	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 main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • For custom data types, the collation must be specified, otherwise the compiler will not know how to sort.

  • Advanced sorting is just another logical rule formulation on the sorting rules and is not complicated.

3.8 set/multiset container

3.8.1 Basic concepts of set

Introduction:

  • All elements will be inAutomatically sorted on insertion

Nature:

  • set/multiset are associative containers , and the underlying structure is implemented using a binary tree .

The difference between set and multiset :

  • set does not allow duplicates in the containerElements
  • multiset allows duplicates in containersElements

3.8.2 set construction and assignment

Function description: Create set container and assign value

structure:

  • set<T> st;//Default constructor:
  • set(const set &st);//copy constructor

Assignment:

  • set& operator=(const set &st);//Overload the equal sign operator

Example:

#include <set>

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

//构造和赋值
void test01()
{
    
    
	set<int> s1;

	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	//所有元素插入时,自动被排序。 不允许插入重复值【不报错,但插入不成功】
	//10 20 30 40
	printSet(s1);

	//拷贝构造
	set<int>s2(s1);
	printSet(s2);

	//赋值
	set<int>s3;
	s3 = s2;
	printSet(s3);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Use insert when inserting data into the set container
  • The data inserted into the set container will be automatically sorted

3.8.3 Set size and exchange

Function description:

  • Count the size of set containers and exchange set containers

Function prototype:

  • size();//Return the number of elements in the container
  • empty();//Determine whether the container is empty
  • swap(st);//Swap two collection containers

Example:

#include <set>

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

//大小
void test01()
{
    
    

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

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

}

//交换
void test02()
{
    
    
	set<int> s1;

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

	set<int> s2;

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

	cout << "交换前" << endl;
	printSet(s1);
	printSet(s2);
	cout << endl;

	cout << "交换后" << endl;
	s1.swap(s2);
	printSet(s1);
	printSet(s2);
}

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Statistical size — size
  • Determine whether it is empty - empty
  • Swap container—swap

3.8.4 set insertion and deletion

Function description:

  • set container to insert data and delete data

Function prototype:

  • insert(elem);//Insert elements into the container.
  • clear();//Clear all elements
  • erase(pos);//Delete the element pointed to by the pos iterator and return the iterator of the next element.
  • erase(beg, end);//Delete all elements in the interval [beg, end) and return the iterator of the next element.
  • erase(elem);//Delete the element whose value is elem in the container.

Example:

#include <set>

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

//插入和删除
void test01()
{
    
    
	set<int> s1;
	//插入
	s1.insert(30);
	s1.insert(10);	
	s1.insert(20);
	s1.insert(40);
	printSet(s1);

	//删除
	s1.erase(s1.begin());
	printSet(s1);

	//删除重载版本
	s1.erase(30);
	printSet(s1);

	//清空
	//s1.erase(s1.begin(), s1.end());
	s1.clear();
	printSet(s1);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • insert — insert
  • Delete—erase
  • clear — clear

3.8.5 set search and statistics

Function description:

  • Search data and statistical data for set containers

Function prototype:

  • find(key);//Check whether the key exists. If it exists, return the iterator of the element of the key; if it does not exist, return set.end();
  • count(key);//Count the number of elements of key

Example:

#include <set>

//查找和统计
void test01()
{
    
    
	set<int> s1;
	//插入
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	
	//查找
	set<int>::iterator pos = s1.find(30);

	if (pos != s1.end())
	{
    
    
		cout << "找到了元素 : " << *pos << endl;
	}
	else
	{
    
    
		cout << "未找到元素" << endl;
	}

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Find — find (returns an iterator)
  • Statistics — count (for set, the result is 0 or 1)

3.8.6 The difference between set and multiset

learning target:

  • Master the difference between set and multiset

the difference:

  • Set cannot insert duplicate data, but multiset can
  • When set inserts data, it will return the insertion result, indicating whether the insertion is successful.
  • multiset does not detect data so duplicate data can be inserted

Example:

#include <set>

//set和multiset区别
void test01()
{
    
    
	set<int> s;
	pair<set<int>::iterator, bool>  ret = s.insert(10);
	cout << "————set容器第一次插入10————" << endl;
	if (ret.second) {
    
     //ret.second 取到第二个bool类型值,true的话表示插入成功
		cout << "第一次插入成功!" << endl;
	}
	else {
    
    
		cout << "第一次插入失败!" << endl;
	}

	cout << "————set容器第二次插入10————" << endl;
	ret = s.insert(10);
	if (ret.second) {
    
    
		cout << "第二次插入成功!" << endl;
	}
	else {
    
    
		cout << "第二次插入失败!" << endl;
	}
    
    cout << "————multiset容器插入2个10————" << endl;
	//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 main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • If inserting duplicate data is not allowed, you can use set
  • If you need to insert duplicate data, use multiset

3.8.7 pair creation

Function description:

  • Data appearing in pairs, using pairs to return two data

Two ways to create:

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

Example:

#include <string>

//pair对组创建
void test01()
{
    
    
	//第一种方式
	pair<string, int> p("Tom", 20);
	cout << "姓名: " <<  p.first << " 年龄: " << p.second << endl;

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

There are two ways to create pairs, just remember one.

3.8.8 set container sorting

learning target:

  • The default sorting rules for set containers are from small to large. Learn how to change the sorting rules.

Main technical points:

  • Using functors , you can change the sorting rules

Example 1 set stores built-in data types

#include <set>

//仿函数 本质上是一个类型
class MyCompare 
{
    
    
public:
	//第一个()表示重载的符号
	//第二个()表示重载符号函数体的参数列表
	bool operator()(int v1, int v2) const{
    
    
		return v1 > v2;
	}
};
void test01() 
{
    
        
	set<int> s1;
	s1.insert(10);
	s1.insert(40);
	s1.insert(20);
	s1.insert(30);
	s1.insert(50);

	//默认从小到大
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;

	//指定排序规则 从大到小
	set<int,MyCompare> s2;
	s2.insert(10);
	s2.insert(40);
	s2.insert(20);
	s2.insert(30);
	s2.insert(50);
	
	//set<int,MyCompare>中的两个形参都是数据类型(int、double等等),不能放一个函数名
	//MyCompare是一种class类型。
	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: Use functors to specify the sorting rules of the set container

Example 2 set stores custom data types

#include <set>
#include <string>

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;
	}
};

void test01()
{
    
    
	set<Person, comparePerson> s;

	Person p1("刘备", 23);
	Person p2("关羽", 27);
	Person p3("张飞", 25);
	Person p4("赵云", 21);

	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;
	}
}
int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

For custom data types, set must specify a collation before it can insert data.

3.9 map/multimap container

3.9.1 Basic concepts of map

Introduction:

  • All elements in map are pairs
  • The first element in the pair is key (key value), which serves as an index, and the second element is value (real value)
  • All elements are automatically sorted based on the element's key value
  • map high efficiency and high performance

Nature:

  • map/multimap is an associative container , and the underlying structure is usingBinary treeaccomplish.

advantage:

  • CanQuickly find value based on key value

The difference between map and multimap :

  • mapDo not allow duplicate key value elements in the container
  • multimapAllow elements with duplicate key values ​​in the container

3.9.2 map construction and assignment

Function description:

  • Construct and assign values ​​to the map container

Function prototype:

structure:

  • map<T1, T2> mp;//map default constructor:
  • map(const map &mp);//copy constructor

Assignment:

  • map& operator=(const map &mp);//Overload the equal sign operator

Example:

#include <map>

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

void test01()
{
    
    
	map<int,int>m; //默认构造
	//pair<int, int>(1, 10) 匿名对组
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	printMap(m);

	map<int, int>m2(m); //拷贝构造
	printMap(m2);

	map<int, int>m3;
	m3 = m2; //赋值
	printMap(m3);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: All elements in the map appear in pairs , and pairs should be used when inserting data.

3.9.3 Map size and swapping

Function description:

  • Count map container sizes and swap map containers

Function prototype:

  • size();//Return the number of elements in the container
  • empty();//Determine whether the container is empty
  • swap(st);//Swap two collection containers

Example:

#include <map>

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

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

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


//交换
void test02()
{
    
    
	map<int, int>m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	map<int, int>m2;
	m2.insert(pair<int, int>(4, 100));
	m2.insert(pair<int, int>(5, 200));
	m2.insert(pair<int, int>(6, 300));

	cout << "交换前" << endl;
	printMap(m);
	printMap(m2);

	cout << "交换后" << endl;
	m.swap(m2);
	printMap(m);
	printMap(m2);
}

int main() {
    
    

	test01();

	test02();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Statistical size — size
  • Determine whether it is empty - empty
  • Swap container—swap

3.9.4 map insertion and deletion

Function description:

  • map container inserts data and deletes data

Function prototype:

  • insert(elem);//Insert elements into the container.
  • clear();//Clear all elements
  • erase(pos);//Delete the element pointed to by the pos iterator and return the iterator of the next element.
  • erase(beg, end);//Delete all elements in the interval [beg, end) and return the iterator of the next element.
  • erase(key);//Delete the element whose value is key in the container.

Example:

#include <map>

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

void test01()
{
    
    
	//插入
	map<int, int> m;
	//第一种插入方式
	m.insert(pair<int, int>(1, 10));
	//第二种插入方式
	m.insert(make_pair(2, 20));
	//第三种插入方式
	m.insert(map<int, int>::value_type(3, 30));
	//第四种插入方式
	m[4] = 40; 
	printMap(m);

	//[]不建议插入,但可以利用key来访问value
	//这里m[5]是没有的,但打印的时候会,自动的创建:key=5 value=0
	cout << m[5] << endl;
	//利用key访问value
	cout << m[4] << endl; //通过key找到对应value值40

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

	//按照key删除
	m.erase(3);
	printMap(m);

	//清空
	m.erase(m.begin(),m.end());
	m.clear();
	printMap(m);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • There are many ways to insert map, just remember one of them
  • insert — insert
  • Delete—erase
  • clear — clear

3.9.5 Map search and statistics

Function description:

  • Search data and statistical data for map containers

Function prototype:

  • find(key);//Check whether the key exists. If it exists, return the iterator of the element of the key; if it does not exist, return set.end();
  • count(key);//Count the number of elements of key

Example:

#include <map>

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

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

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

	//统计
	//map不允许插入重复key元素,count统计而言 结果要么是0 要么是1
	int num = m.count(3);
	cout << "m中key=3的数量为:" << num << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Find — find (returns an iterator)
  • Statistics — count (for map, the result is 0 or 1)

3.9.6 Map container sorting

learning target:

  • The default sorting rule of the map container is to sort from small to large according to the key value. Learn how to change the sorting rules.

Main technical points:

  • Using functors, you can change the sorting rules

Example:

#include <map>

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

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

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

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

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Use functors to specify the sorting rules of the map container
  • For custom data types, map must specify sorting rules, the same as set container

3.10 Case-Employee Grouping

3.10.1 Case description

  • The company recruited 10 employees (ABCDEFGHIJ) today. After the 10 employees join the company, they need to be assigned to work in that department.
  • Employee information includes: name, salary composition; departments are divided into: planning, art, research and development
  • Randomly assign departments and salaries to 10 employees
  • Insert information through multimap key (department number) value (employee)
  • Display employee information by department

3.10.2 Implementation steps

  1. Create 10 employees and put them in vector
  2. Traverse the vector container, take out each employee, and group them randomly
  3. After grouping, use the employee department number as the key and the specific employee as the value, and put them into the multimap container.
  4. Display employee information by department

Case code:

#include<iostream>
using namespace std;
#include <vector>
#include <string>
#include <map>
#include <ctime>

/*
- 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
- 员工信息有: 姓名  工资组成;部门分为:策划、美术、研发
- 随机给10名员工分配部门和工资
- 通过multimap进行信息的插入  key(部门编号) value(员工)
- 分部门显示员工信息
*/

#define CEHUA  0
#define MEISHU 1
#define YANFA  2

class Worker
{
    
    
public:
	string m_Name;
	int m_Salary;
};

//1、创建员工分组
void createWorker(vector<Worker>&v)
{
    
    
	string nameSeed = "ABCDEFGHIJ";
	for (int i = 0; i < 10; i++)
	{
    
    
		Worker worker;
		worker.m_Name = "员工";
		worker.m_Name += nameSeed[i];

		worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999
		//将员工放入到容器中
		v.push_back(worker);
	}
}

//2、员工分组
void setGroup(vector<Worker>&v,multimap<int,Worker>&m)
{
    
    
	for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
	{
    
    
		//产生随机部门编号
		int deptId = rand() % 3; // 0 1 2 

		//将员工插入到分组中
		//key部门编号,value具体员工
		m.insert(make_pair(deptId, *it));
	}
}

//3、分组显示员工
void showWorkerByGourp(multimap<int,Worker>&m)
{
    
    
	// 0  A  B  C   1  D  E   2  F G ...
	cout << "策划部门:" << endl;

	multimap<int,Worker>::iterator pos = m.find(CEHUA);
	int count = m.count(CEHUA); // 统计策划部具体人数
	int index = 0;
	for (; pos != m.end() && index < count; pos++ , index++)
	{
    
    
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "美术部门: " << endl;
	pos = m.find(MEISHU);
	count = m.count(MEISHU); // 统计具体人数
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
    
    
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "研发部门: " << endl;
	pos = m.find(YANFA);
	count = m.count(YANFA); // 统计具体人数
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
    
    
		cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
	}

}

int main() {
    
    

	srand((unsigned int)time(NULL));

	//1、创建员工
	vector<Worker>vWorker;
	createWorker(vWorker);

	//2、员工分组
	multimap<int, Worker>mWorker;
	setGroup(vWorker, mWorker);


	//3、分组显示员工
	showWorkerByGourp(mWorker);

	测试
	//for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++)
	//{
    
    
	//	cout << "姓名: " << it->m_Name << " 工资: " << it->m_Salary << endl;
	//}

	system("pause");

	return 0;
}

Summarize:

  • When data exists in the form of key-value pairs, consider using map or multimap

4 STL- Function Object

4.1 Function object

4.1.1 Function object concept

concept:

  • A class that overloads the function call operator . Its object is often called a function object.
  • When a function object uses overloaded () , it behaves like a function call, also called a functor.

Nature:

A function object (functor) is a class, not a function

4.1.2 Use of function objects

Features:

  • When a function object is used, it can be called like a normal function, with parameters and return values.
  • Function objects go beyond the concept of ordinary functions. Function objects can have their own state.
  • Function objects can be passed as arguments

Example:

#include <string>

//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
    
    
public :
	int operator()(int v1,int v2)
	{
    
    
		return v1 + v2;
	}
};
void test01()
{
    
    
	MyAdd myAdd;
	cout << myAdd(10, 10) << endl; //20
}

//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");
	cout << "myPrint调用次数为: " << myPrint.count << endl;
}

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

int main() {
    
    

	//test01();
	//test02();
	test03();

	system("pause");

	return 0;
}

Insert image description here

Summarize:

  • Functor writing is very flexible and can be passed as parameters.

4.2 Predicate

4.2.1 Predicate concept

concept:

  • Returns a functor of type boolcalled predicate
  • if operator()accepts a parameter, then it is calledunary predicate
  • if operator()accepts two parameters, then it is calledbinary predicate

4.2.2 Unary predicate

Example:

#include <vector>
#include <algorithm>

 //返回bool类型的仿函数称为谓词
//1.一元谓词 operator()接受一个参数
class GreaterFive{
    
    
public:
	bool operator()(int val) const{
    
    
		return val > 5;
	}
};

void test01() {
    
    

	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 << "找到:" << *it << endl;
	}

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: A predicate with only one parameter is called a unary predicate

4.2.3 Binary predicate

Example:

#include <vector>
#include <algorithm>
//二元谓词
class MyCompare
{
    
    
public:
	bool operator()(int num1, int num2)const
	{
    
    
		return num1 > num2;
	}
};

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

	//默认从小到大
	sort(v.begin(), v.end());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
	cout << "----------------------------" << endl;

	//使用函数对象改变算法策略,排序从大到小
	sort(v.begin(), v.end(), MyCompare());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: A predicate with only two parameters is called a binary predicate

4.3 Built-in function objects

4.3.1 Meaning of built-in function objects

concept:

  • STL has some built-in function objects

Classification:

  • arithmetic functor

  • Relation functor

  • logical functor

usage:

  • The objects generated by these functors can be used exactly the same as ordinary functions.
  • To use built-in function objects, you need to introduce header files#include<functional>

4.3.2 Arithmetic functors

Function description:

  • Implement four arithmetic operations
  • Among them, negate is a unary operation, and the others are binary operations.

Functor prototype:

  • template<class T> T plus<T>//addition functor
  • template<class T> T minus<T>//Subtraction functor
  • template<class T> T multiplies<T>//Multiplication functor
  • template<class T> T divides<T>//division functor
  • template<class T> T modulus<T>//Get the imitation function
  • template<class T> T negate<T>//Get the inverse function

Example:

#include <functional>
//negate 一元仿函数 取反仿函数
void test01()
{
    
    
	negate<int> n;
	cout << n(50) << endl; //-50
}

//plus 二元仿函数 加法
void test02()
{
    
    
	//默认传入的是同一种类型的数
	plus<int> p;
	cout << p(10, 20) << endl; //30
}

int main() {
    
    

	test01();
	test02();

	system("pause");

	return 0;
}

Insert image description here

Summary: When using built-in function objects, you need to introduce header files#include <functional>

4.3.3 Relational functors

Function description:

  • Realize relationship comparison

Functor prototype:

  • template<class T> bool equal_to<T>//equal
  • template<class T> bool not_equal_to<T>//not equal to
  • template<class T> bool greater<T>//more than the
  • template<class T> bool greater_equal<T>//greater or equal to
  • template<class T> bool less<T>//Less than
  • template<class T> bool less_equal<T>//less than or equal to

Example:

#include <functional>
#include <vector>
#include <algorithm>

class MyCompare
{
    
    
public:
	bool operator()(int v1,int v2)
	{
    
    
		return v1 > v2;
	}
};
void test01()
{
    
    
	vector<int> v;

	v.push_back(10);
	v.push_back(30);
	v.push_back(50);
	v.push_back(40);
	v.push_back(20);

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

	//自己实现仿函数
	//sort(v.begin(), v.end(), MyCompare());
	//STL内建仿函数  大于仿函数
	sort(v.begin(), v.end(), greater<int>());

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: The most commonly used relational functor is greater<> greater than

4.3.4 Logical functors

Function description:

  • Implement logical operations

Function prototype:

  • template<class T> bool logical_and<T>//Logical AND
  • template<class T> bool logical_or<T>//logical or
  • template<class T> bool logical_not<T>//logical negation

Example:

#include <vector>
#include <functional>
#include <algorithm>
void test01()
{
    
    
	vector<bool> v;
	v.push_back(true);
	v.push_back(false);
	v.push_back(true);
	v.push_back(false);

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

	//逻辑非  将v容器搬运到v2中,并执行逻辑非运算
	vector<bool> v2;
	//v2容器扩大到v1容器大小
	v2.resize(v.size());
	//transform 搬运算法
	transform(v.begin(), v.end(),  v2.begin(), logical_not<bool>());
	for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Insert image description here

Summary: Logic functors have few practical applications, just understand them

5 STL- Commonly used algorithms

Overview :

  • The algorithm mainly <algorithm> <functional> <numeric>consists of header files.

  • <algorithm>It is the largest of all STL header files , covering comparison, exchange, search, traversal operations, copying, modification, etc.

  • <numeric>It is small in size and includes only a few template functions that perform simple mathematical operations on sequences.

  • <functional>Some template classes are defined to declare function objects.

5.1 Commonly used traversal algorithms

learning target:

  • Master commonly used traversal algorithms

Algorithm introduction:

  • for_each//Traverse the container
  • transform//Move the container to another container

5.1.1 for_each

Function description:

  • Implement traversal of containers

Function prototype:

  • for_each(iterator beg, iterator end, _func);

    // Traversal algorithm traverses container elements

    // beg starts the iterator

    // end ends the iterator

    // _func function or function object

Example:

#include <algorithm>
#include <vector>

//普通函数
void print01(int val) 
{
    
    
	cout << val << " ";
}
//函数对象 仿函数
class print02 
{
    
    
 public:
	void operator()(int val) 
	{
    
    
		cout << val << " ";
	}
};

//for_each算法基本用法
void test01() {
    
    

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

	//遍历算法
	for_each(v.begin(), v.end(), print01);
	cout << endl;

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : for_each is the most commonly used traversal algorithm in actual development and requires proficiency.

5.1.2 transform

Function description:

  • Move container to another container

Function prototype:

  • transform(iterator beg1, iterator end1, iterator beg2, _func);

//beg1 source container starts iterator

//end1 source container end iterator

//beg2 target container starts iterator

//_func function or function object

Example:

#include<vector>
#include<algorithm>

//常用遍历算法  搬运 transform

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

};

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

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

	vector<int>vTarget; //目标容器

	vTarget.resize(v.size()); // 目标容器需要提前开辟空间

	transform(v.begin(), v.end(), vTarget.begin(), TransForm());

	for_each(vTarget.begin(), vTarget.end(), MyPrint());
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary: The target container for transportation must open up space in advance, otherwise it cannot be transported normally.

5.2 Common search algorithms

learning target:

  • Master common search algorithms

Algorithm introduction:

  • find//Find element
  • find_if//Find elements based on conditions
  • adjacent_find//Find adjacent duplicate elements
  • binary_search//binary search method
  • count//Count the number of elements
  • count_if//Count the number of elements according to conditions

5.2.1 find

Function description:

  • Find the specified element, find the iterator that returns the specified element, and find the iterator that returns the end iterator end()

Function prototype:

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

    // Search for elements by value. If found, return the specified position iterator. If not found, return the end iterator position.

    // beg starts the iterator

    // end ends the iterator

    // value element to find

Example:

#include <algorithm>
#include <vector>
#include <string>

//查找内置数据类型
void test01() {
    
    

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

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

public:
	string m_Name;
	int m_Age;
};

//查找自定义数据类型
void test02() {
    
    

	vector<Person> v;

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

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

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

Summary: Use find to find the specified element in the container, and the return value is an iterator

5.2.2 find_if

Function description:

  • Find elements by condition

Function prototype:

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

    // Search for elements by value. If found, return the specified position iterator. If not found, return the end iterator position.

    // beg starts the iterator

    // end ends the iterator

    // _Pred function or predicate (returns bool type functor)

Example:

#include <algorithm>
#include <vector>
#include <string>


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

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

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

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

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

};

void test02() {
    
    

	vector<Person> v;

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

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

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

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: find_if searches by condition to make the search more flexible, and the provided functor can change different strategies

5.2.3 adjacent_find

Function description:

  • Find adjacent duplicate elements

Function prototype:

  • adjacent_find(iterator beg, iterator end);

    // Find adjacent duplicate elements and return the iterator of the first position of the adjacent element

    // beg starts the iterator

    // end ends the iterator

Example:

#include <algorithm>
#include <vector>

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

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

Summary: If you need to find adjacent repeated elements in an interview question, remember to use the adjacent_find algorithm in STL.

5.2.4 binary_search

Function description:

  • Find whether the specified element exists

Function prototype:

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

    //Find the specified element and return true if found, otherwise false

    // Note: Not available in unordered sequences

    // beg starts the iterator

    // end ends the iterator

    // value element to find

Example:

#include <algorithm>
#include <vector>

void test01()
{
    
    
	vector<int>v;

	for (int i = 0; i < 10; i++)
	{
    
    
		v.push_back(i);
	}
	//二分查找 查找容器中是否有2元素
	//注意:这个容器必须是有序且升序的序列   降序序列也不行
	bool ret = binary_search(v.begin(), v.end(),2);
	if (ret)
	{
    
    
		cout << "找到了" << endl;
	}
	else
	{
    
    
		cout << "未找到" << endl;
	}
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : The binary search method is very efficient. It is worth noting that the elements in the container must be in an ordered sequence.

5.2.5 count

Function description:

  • Number of statistical elements

Function prototype:

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

    // Count the number of occurrences of elements

    // beg starts the iterator

    // end ends the iterator

    // value element of statistics

Example:

#include <algorithm>
#include <vector>

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

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

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

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

void test02()
{
    
    
	vector<Person> v;

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

	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
    
    Person p("诸葛亮",35);

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

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: When counting custom data types, you need to cooperate with overloadingoperator==

5.2.6 count_if

Function description:

  • Count the number of elements according to conditions

Function prototype:

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

    // Count the number of occurrences of elements based on conditions

    // beg starts the iterator

    // end ends the iterator

    // _Pred predicate

Example:

#include <algorithm>
#include <vector>

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

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

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

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

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

	string m_Name;
	int m_Age;
};

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

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

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

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


int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

**Summary:** Use count for statistics by value, and count_if for statistics based on conditions.

5.3 Commonly used sorting algorithms

learning target:

  • Master commonly used sorting algorithms

Algorithm introduction:

  • sort//Sort the elements in the container
  • random_shuffle//Shuffle the elements within the specified range and randomly adjust the order
  • merge // Container elements are merged and stored in another container
  • reverse//Reverse the elements in the specified range

5.3.1 sort

Function description:

  • Sort elements within a container

Function prototype:

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

    // Search for elements by value. If found, return the specified position iterator. If not found, return the end iterator position.

    // beg starts the iterator

    // end ends the iterator

    // _Pred predicate

Example:

#include <algorithm>
#include <vector>

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

**Summary: **sort is one of the most commonly used algorithms in development and requires proficiency.

5.3.2 random_shuffle

Function description:

  • Shuffle the elements in the specified range and randomly adjust the order

Function prototype:

  • random_shuffle(iterator beg, iterator end);

    // Randomly adjust the order of elements within the specified range

    // beg starts the iterator

    // end ends the iterator

Example:

#include <algorithm>
#include <vector>
#include <ctime>

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : The random_shuffle shuffling algorithm is more practical. Remember to add a random number seed when using it.

5.3.3 merge

Function description:

  • Two container elements are merged and stored in another container

Function prototype:

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

    // Container elements are merged and stored in another container

    // Note: The two containers must be ordered

    // beg1 is the beginning iterator of container 1
    // end1 is the end iterator of container 1
    // beg2 is the beginning iterator of container 2
    // end2 is the end iterator of container
    2 // dest is the beginning iterator of the target container

Example:

#include <algorithm>
#include <vector>

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : The ordered sequence required to merge the two containers

5.3.4 reverse

Function description:

  • Reverse the elements in the container

Function prototype:

  • reverse(iterator beg, iterator end);

    //Reverse the elements in the specified range

    // beg starts the iterator

    // end ends the iterator

Example:

#include <algorithm>
#include <vector>

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

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : reverse reverses the elements in the interval, which may be involved in interview questions

5.4 Common copy and replacement algorithms

learning target:

  • Master common copy and replacement algorithms

Algorithm introduction:

  • copy//Copy the specified range of elements in the container to another container
  • replace// Modify the old elements in the specified range in the container to new elements
  • replace_if //Replace the elements in the container that meet the conditions in the specified range with new elements
  • swap// Swap the elements of the two containers

5.4.1 copy

Function description:

  • Copies the specified range of elements in the container to another container

Function prototype:

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

    // Search for elements by value. If found, return the specified position iterator. If not found, return the end iterator position.

    // beg starts the iterator

    // end ends the iterator

    // dest target starting iterator

Example:

#include <algorithm>
#include <vector>

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : When copying using the copy algorithm, remember to open up space in the target container in advance.

5.4.2 replace

Function description:

  • Modify the old elements in the specified range of the container to new elements

Function prototype:

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

    //Replace old elements in the range with new elements

    // beg starts the iterator

    // end ends the iterator

    // oldvalue old element

    // newvalue new element

Example:

#include <algorithm>
#include <vector>

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : replace will replace elements within the interval that meet the conditions

5.4.3 replace_if

Function description:

  • Replace the elements that meet the condition in the interval with the specified element

Function prototype:

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

    //Replace elements according to conditions, and replace elements that meet the conditions with specified elements

    // beg starts the iterator

    // end ends the iterator

    // _pred predicate

    // new value replaced new element

Example:

#include <algorithm>
#include <vector>

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

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

};

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : replace_if searches according to conditions, and you can use functors to flexibly filter the conditions that are met.

5.4.4 swap

Function description:

  • Swap the elements of two containers

Function prototype:

  • swap(container c1, container c2);

    // Swap the elements of the two containers

    // c1 container 1

    // c2 container 2

Example:

#include <algorithm>
#include <vector>

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : When swapping containers, pay attention to the fact that the containers exchanged must be of the same type.

5.5 Commonly used arithmetic generation algorithms

learning target:

  • Master common arithmetic generation algorithms

Notice:

  • The arithmetic generation algorithm is a small algorithm, and the header file included when using it is#include <numeric>

Algorithm introduction:

  • accumulate// Calculate the cumulative sum of container elements

  • fill//Add elements to the container

5.5.1 accumulate

Function description:

  • Calculate the cumulative sum of container elements in a range

Function prototype:

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

    // Calculate the cumulative sum of container elements

    // beg starts the iterator

    // end ends the iterator

    // value starting value

Example:

#include <numeric>
#include <vector>
void test01()
{
    
    
	vector<int> v;
	for (int i = 0; i <= 100; i++) {
    
    
		v.push_back(i);
	}

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : When using accumulate, please note that the header file is numeric. This algorithm is very practical.

5.5.2 fill

Function description:

  • Fills the container with the specified elements

Function prototype:

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

    // Fill the container with elements

    // beg starts the iterator

    // end ends the iterator

    // value filled value

Example:

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

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

void test01()
{
    
    

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summary : Use fill to fill the elements in the container range with specified values.

5.6 Common set algorithms

learning target:

  • Master common set algorithms

Algorithm introduction:

  • set_intersection// Find the intersection of two containers

  • set_union// Find the union of two containers

  • set_difference // Find the difference between two containers

5.6.1 set_intersection

Function description:

  • Find the intersection of two containers

Function prototype:

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

    // Find the intersection of two sets

    // Note: The two sets must be ordered sequences

    // beg1 is the beginning iterator of container 1
    // end1 is the end iterator of container 1
    // beg2 is the beginning iterator of container 2
    // end2 is the end iterator of container
    2 // dest is the beginning iterator of the target container

Example:

#include <vector>
#include <algorithm>

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

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summarize:

  • Find the necessary ordered sequence for the intersection of two sets
  • The target container needs to take the smaller value from the two containers to open up space.
  • The return value of set_intersection is the position of the last element in the intersection

5.6.2 set_union

Function description:

  • Find the union of two sets

Function prototype:

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

    // Find the union of two sets

    // Note: The two sets must be ordered sequences

    // beg1 is the beginning iterator of container 1
    // end1 is the end iterator of container 1
    // beg2 is the beginning iterator of container 2
    // end2 is the end iterator of container
    2 // dest is the beginning iterator of the target container

Example:

#include <vector>
#include <algorithm>

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

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summarize:

  • Find the necessary ordered sequence for the union of two sets
  • The target container requires the addition of two containers to open up space.
  • The return value of set_union is the position of the last element in the union

5.6.3 set_difference

Function description:

  • Find the difference between two sets

Function prototype:

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

    // Find the difference between two sets

    // Note: The two sets must be ordered sequences

    // beg1 is the beginning iterator of container 1
    // end1 is the end iterator of container 1
    // beg2 is the beginning iterator of container 2
    // end2 is the end iterator of container
    2 // dest is the beginning iterator of the target container

Example:

#include <vector>
#include <algorithm>

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

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

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

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


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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Summarize:

  • Find the necessary ordered sequence of two sets of difference sets
  • The target container needs to take the larger value from the two containers to open up space.

Guess you like

Origin blog.csdn.net/isak233/article/details/131680705