【C++】Improve programming

This article is a reprint of part of the handouts of "Dark Horse Programmer C++ Tutorial". It is for learning purposes only and is convenient for reference.

C++ improves programming

Article directory

  • 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:

Please add image description

PPT template:
Please add image description

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 — 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:


//交换整型函数
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;
}

Summarize:

  • Function templates use the keyword template
  • There are two ways to use function templates: automatic type deduction and display of specified types.
  • 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;
}

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

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("孙悟空", 999);
	P1.showPerson();
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

There is a difference between the creation timing of member functions in class templates and member functions in ordinary classes:

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

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

There are three 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;
}

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

//类模板继承类模板 ,可以用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;
}

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

Summary: When implementing member functions in a class template outside the class, you need to add a template parameter list

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:

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、全局函数配合友元  类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元
template<class T1, class T2> class Person;

//如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到
//template<class T1, class T2> void printPerson2(Person<T1, T2> & p); 

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

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;
		pAddress = new T[this->m_Capacity];
	}

	//拷贝构造
	MyArray(const MyArray & arr)
	{
    
    
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[this->m_Capacity];
		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->m_Capacity = myarray.m_Capacity;
		this->m_Size = myarray.m_Size;
		this->pAddress = new T[this->m_Capacity];
		for (int i = 0; i < this->m_Size; i++) {
    
    
			this->pAddress[i] = myarray[i];
		}
		return *this;
	}

	//重载[] 操作符  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;
		}
		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;   // 大小
};

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

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: container, algorithm, iterator, functor, adapter (adapter), and space configurator

  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: **Place for storage

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 :

​Sequential container : Emphasizes the ordering of values. Each element in the sequential container has a fixed position.
Associative container : binary tree structure, there is no strict physical order relationship between elements

**Algorithm: **The solution to the problem

Limited steps are used to solve logical or mathematical problems. This subject is called Algorithms.

The algorithm is divided into: qualitative change algorithm and non-qualitative change algorithm .

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

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

**Iterators:** The glue between containers and algorithms

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

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("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);
	Person p5("eee", 50);

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

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

	}
}


//放对象指针
void test02() {
    
    

	vector<Person*> v;

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

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

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


int main() {
    
    

	test01();
    
	test02();

	system("pause");

	return 0;
}

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++) {
    
    

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

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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
  • 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');
	cout << "str3 = " << s3 << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

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

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

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

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

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

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

**Summary:** The starting subscripts of 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;
}

**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.

Please add image description

  • 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 v[begin(), end()) interval 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()
{
    
    
	vector<int> v1; //无参构造
	for (int i = 0; i < 10; i++)
	{
    
    
		v1.push_back(i);
	}
	printVector(v1);

	vector<int> v2(v1.begin(), v1.end());
	printVector(v2);

	vector<int> v3(10, 100);
	printVector(v3);
	
	vector<int> v4(v3);
	printVector(v4);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

**Summary: **The various construction methods of vector are not comparable, so you can 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);

	vector<int>v2;
	v2 = v1;
	printVector(v2);

	vector<int>v3;
	v3.assign(v1.begin(), v1.end());
	printVector(v3);

	vector<int>v4;
	v4.assign(10, 100);
	printVector(v4);
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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);
	v1.push_back(50);
	printVector(v1);
	//尾删
	v1.pop_back();
	printVector(v1);
	//插入
	v1.insert(v1.begin(), 100);
	printVector(v1);

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

	//删除
	v1.erase(v1.begin());
	printVector(v1);

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

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

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

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

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.

Example:

#include <vector>

void test01()
{
    
    
	vector<int> v;

	//预留空间
	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;
}

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.

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

  • 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) 
{
    
    
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
    
    
		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;
}

**Summary: **The construction methods of deque container and vector container 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);

	deque<int>d2;
	d2 = d1;
	printDeque(d2);

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

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

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

Summarize:

  • deque has no concept of capacity
  • 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> d;
	d.push_back(10);
	d.push_back(20);
	d.push_front(100);
	d.push_front(200);
	printDeque(d);

	d.insert(d.begin(), 1000);
	printDeque(d);

	d.insert(d.begin(), 2,10000);
	printDeque(d);

	deque<int>d2;
	d2.push_back(1);
	d2.push_back(2);
	d2.push_back(3);

	d.insert(d.begin(), d2.begin(), d2.end());
	printDeque(d);

}

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

	d.erase(d.begin());
	printDeque(d);

	d.erase(d.begin(), d.end());
	d.clear();
	printDeque(d);
}

int main() {
    
    

	//test01();

	//test02();

    test03();
    
	system("pause");

	return 0;
}

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

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

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

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 ratings 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;  //平均分
};

void createPerson(vector<Person>&v)
{
    
    
	string nameSeed = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
    
    
		string name = "选手";
		name += nameSeed[i];

		int score = 0;

		Person p(name, score);

		//将创建的person对象 放入到容器中
		v.push_back(p);
	}
}

//打分
void setScore(vector<Person>&v)
{
    
    
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
    
    
		//将评委的分数 放入到deque容器中
		deque<int>d;
		for (int i = 0; i < 10; i++)
		{
    
    
			int score = rand() % 41 + 60;  // 60 ~ 100
			d.push_back(score);
		}

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

}

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

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 a first in last out (FILO) data structure, which has only one outlet.

Insert image description here

Only the top elements in the stack can be used by the outside world, so the stack does not allow traversal behavior.

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

Popping data from the stack is called popping pop

Stack in life:
Insert image description here
Insert image description here

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

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 a first in first out (FIFO) data structure, which has two exits

Insert image description here

A queue container allows adding elements from one end and removing elements from the other end.

Only the head and tail of the queue can be used by the outside world, so the 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("唐僧", 30);
	Person p2("孙悟空", 1000);
	Person p3("猪八戒", 900);
	Person p4("沙僧", 800);

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

	//队列不提供迭代器,更不支持随机访问	
	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;
}

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:** Store data in a chain

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 the node: one is the data field that stores data elements, and the other is the pointer field that stores the address of the next node.

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

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

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

	//赋值
	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;
}

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

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) range at position pos, no return value.
  • clear();//Remove all data from the container
  • erase(beg,end);//Delete the data in [beg,end) range, and return the position of the next data.
  • erase(pos);//Delete the data at position pos and return the position of the next data.
  • remove(elem);//Delete all elements in the container that match the value of elem.

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

	printList(L);

	//尾删
	L.pop_back();
	printList(L);

	//头删
	L.pop_front();
	printList(L);

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

	//删除
	it = L.begin();
	L.erase(++it);
	printList(L);

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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; //错误  不支持[]方式访问数据
	cout << "第一个元素为: " << L1.front() << endl;
	cout << "最后一个元素为: " << L1.back() << endl;

	//list容器的迭代器是双向迭代器,不支持随机访问
	list<int>::iterator it = L1.begin();
	//it = it + 1;//错误,不可以跳跃访问,即使是+1
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

	//排序
	L.sort(); //默认的排序规则 从小到大
	printList(L);

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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 are automatically sorted when inserted

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 duplicate elements in the container
  • multiset allows duplicate elements in the container

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);
	printSet(s1);

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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(10);
	s1.insert(30);
	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;
}

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

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);
	if (ret.second) {
    
    
		cout << "第一次插入成功!" << endl;
	}
	else {
    
    
		cout << "第一次插入失败!" << endl;
	}

	ret = s.insert(10);
	if (ret.second) {
    
    
		cout << "第二次插入成功!" << endl;
	}
	else {
    
    
		cout << "第二次插入失败!" << 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;
}

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>

//对组创建
void test01()
{
    
    
	pair<string, int> p(string("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;
}

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

	for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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)
	{
    
    
		//按照年龄进行排序  降序
		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;
}

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

Nature:

  • Map/multimap is an associative container , and the underlying structure is implemented using a binary tree.

advantage:

  • You can quickly find the value based on the key value

The difference between map and multimap :

  • map does not allow duplicate key value elements in the container
  • Multimap allows duplicate key value elements 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; //默认构造
	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;
}

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

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

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

	m.erase(3);
	printMap(m);

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

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

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

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

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

//员工分组
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));
	}
}

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 parameters

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

//2、函数对象可以有自己的状态
class MyPrint
{
    
    
public:
	MyPrint()
	{
    
    
		count = 0;
	}
	void operator()(string test)
	{
    
    
		cout << test << endl;
		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;
}

Summarize:

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

4.2 Predicate

4.2.1 Predicate concept

concept:

  • Functors that return bool type are called predicates
  • If operator() accepts one parameter, it is called a unary predicate
  • If operator() accepts two parameters, it is called a binary predicate

4.2.2 Unary predicate

Example:

#include <vector>
#include <algorithm>

//1.一元谓词
struct GreaterFive{
    
    
	bool operator()(int val) {
    
    
		return val > 5;
	}
};

void test01() {
    
    

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

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

}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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

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

//plus
void test02()
{
    
    
	plus<int> p;
	cout << p(10, 20) << endl;
}

int main() {
    
    

	test01();
	test02();

	system("pause");

	return 0;
}

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

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.resize(v.size());
	transform(v.begin(), v.end(),  v2.begin(), logical_not<bool>());
	for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++)
	{
    
    
		cout << *it << " ";
	}
	cout << endl;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

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)
	{
    
    
		return val > 5;
	}
};

void test01() {
    
    

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

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

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

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

};

void test02() {
    
    

	vector<Person> v;

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

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

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

int main() {
    
    

	//test01();

	test02();

	system("pause");

	return 0;
}

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);
	}
	//二分查找
	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 based on 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: **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: **Merge merges the two containers in an ordered sequence that must be

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 that meet the conditions in the interval

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 exchanged containers 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.
  • The return value of set_difference is the position of the last element in the difference set

Guess you like

Origin blog.csdn.net/iiinoname/article/details/124753079