C++ improves programming study notes, with code

 Dark Horse Programmer C++ Study Notes 01 Template-Template Concept_哔哩哔哩_bilibili


 

Table of contents

1 template

1.1 The concept of a template

1.2 Function Templates

1.2.1 Function template syntax

1.2.2 Function template considerations

1.2.3 Function template case

1.2.4 The difference between ordinary functions and function templates

1.2.5 Calling rules for ordinary functions and function templates

1.2.6 Limitations of Templates

1.3 Class Templates

1.3.1 Class template syntax

1.3.2 Difference between class template and function template

1.3.3 When to create a member function in a class template

1.3.4 Class template object as function parameter

1.3.5 Class Templates and Inheritance

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

1.3.7 Class Template File Compilation

1.3.8 Class templates and friends

1.3.9 Class template example

2 Introduction to STL

2.1 The birth of STL

2.2 Basic concepts of STL

2.3 Six components of STL

2.4 Containers, Algorithms, Iterators in STL

2.5 Introduction to container algorithm iterators

2.5.1 vector stores built-in data types

2.5.2 Vector stores custom data types

2.5.3 Vector container nested container

3 STL-Common container

3.1 string container

3.1.1 Basic concept of string

3.1.2 String constructor

3.1.3 String assignment operation

3.1.4 String concatenation

3.1.5 string search and replace

3.1.6 string string comparison

3.1.7 string character access

3.1.8 string insertion and deletion

3.1.9 string substring

3.2 vector container

3.2.1 Basic concept of vector

3.2.2 vector constructor

3.2.3 Vector assignment operation

3.2.4 Vector capacity and size

3.2.5 vector insertion and deletion

3.2.6 vector data access

3.2.7 vector swap container

3.2.8 vector reserved space

3.3 deque container

3.3.1 Basic concept of deque container

3.3.2 deque constructor

3.3.3 deque assignment operation

3.3.4 Deque size operation

3.3.5 deque insertion and deletion

3.3.6 deque data access

3.3.7 deque sorting

3.4 Case - judges scoring

3.4.1 Case description

3.4.2 Implementation steps

3.5 stack container

3.5.1 Basic concept of stack

3.5.2 Stack common interface

3.6 queue container

3.6.1 Basic concept of queue

3.6.2 Queue common interface

3.7 list container

3.7.1 Basic concept of list

3.7.2 list constructor

3.7.3 list assignment and exchange

3.7.4 List Size Operations

3.7.5 list insertion and deletion

3.7.6 list data access

3.7.7 List inversion and sorting

3.7.8 Sorting case

3.8 set/ multiset containers

3.8.1 Basic concept of set

3.8.2 Set construction and assignment

3.8.3 Set size and swap

3.8.4 set insertion and deletion

3.8.5 set search and statistics

3.8.6 Difference between set and multiset

3.8.7 Create a pair

3.8.8 Set container sorting

3.9 map/multimap container

3.9.1 Basic concept of map

3.9.2 map construction and assignment

3.9.3 Map size and swapping

3.9.4 Map insertion and deletion

3.9.5 Map search and statistics

3.9.6 Map container sorting

3.10 Case - Employee Grouping

3.10.1 Case description

3.10.2 Implementation steps

4 STL-Function Objects

4.1 Function objects

4.1.1 Function object concept

4.1.2 Function Object Usage

4.2 Predicates

4.2.1 Predicate concept

4.2.2 Unary predicates

4.2.3 Binary predicates

4.3 Built-in function objects

4.3.1 The meaning of built-in function object

4.3.2 Arithmetic functors

4.3.3 Relational functors

4.3.4 Logical functors

5 STL-Common Algorithms

5.1 Commonly used traversal algorithms

5.1.1 for_each

5.1.2 transform

5.2 Common search algorithms

5.2.1 find

5.2.2 find_if

5.2.3 adjacent_find

5.2.4 binary_search

5.2.5 count

5.2.6 count_if

5.3 Common sorting algorithms

5.3.1 sort

5.3.2 random_shuffle

5.3.3 merge

5.3.4 reverse

5.4 Common Copy and Replace Algorithms

5.4.1 copy

5.4.2 replace

5.4.3 replace_if

5.4.4 swap

5.5 Common Arithmetic Generation Algorithms

5.5.1 accumulate

5.5.2 fill

5.6 Common Set Algorithms

5.6.1 set_intersection

5.6.2 set_union

5.6.3 set_difference


 This stage mainly focuses on the detailed explanation of C++ generic programming and STL technology, and explores the deeper use of C++

1 template

1.1 The concept of a template

The template is to create a general mold , which greatly improves the reusability

Features of the template:

  • The template cannot be used directly, it is just a framework

  • The generality of the template is not a panacea

1.2 Function Templates

  • Another programming idea in C++ is called generic programming , and the main technology used is templates.

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

 

1.2.1 Function template syntax

Function template role:

To create a general function, its function return value type and formal parameter type can not be specified, but can be represented by a virtual type .

 grammar:

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

 

explain:

template --- Declare the creation template

typename --- The symbol behind it on the surface is a data type, which can be replaced by class

T --- general data type, the name can be replaced, usually an uppercase letter

 

 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 explicit specified type

  • The purpose of the template is to improve reusability and parameterize the type

1.2.2 Function template considerations

Precautions:

  • Automatic type deduction, must deduce 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>//typename可以替换成class
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, the general data type T must be determined, and a consistent type can be deduced

 

1.2.3 Function template case

Case description:

  • Use the function template to encapsulate a sorting function, which can sort arrays of different data types

  • The sorting rules are from large to small, and the sorting algorithm is selection sort

  • Test with 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 need to be mastered

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 ordinary function calls

  • When the function template is called, if automatic type deduction is used, no implicit type conversion will occur

  • Implicit type conversions can occur if the explicit type is 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 to call 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 the function template and the normal function can be implemented, the normal function is called first

  2. Function templates can be forced to be invoked 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 appear

 

1.2.6 Limitations of Templates

 

limitation:

  • Template versatility is not everything

 For example:

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

The assignment operation provided in the above code cannot be realized if a and b passed in 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:

  • Generalization of custom types can be solved by using concrete templates

  • Learning templates is not to write templates, but to use the templates provided by the system in STL

 

1.3 Class Templates

 

1.3.1 Class template syntax

Class template role:

  • Create a general class, the data type of the members in the class can be represented by a virtual type without specifying .

 grammar:

template<typename T>
类

explain:

template --- Declare the creation template

typename --- The symbol behind it on the surface is a data type, which can be replaced by class

T --- general data type, the name can be replaced, usually an uppercase letter

 

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: Class templates and function templates have similar syntax. Add a class after the declaration template template, which is called a class template

1.3.2 Difference between class template and function template

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

  1. The use of class templates without automatic type deduction

  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 explicitly specify the type

  • Template parameter lists in class templates can have default parameters

 

1.3.3 When to create a member function in a class template

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

  • Member functions in ordinary classes can be created at the outset

  • Member functions in class templates are created when they are 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: The member functions in the class template are not created at the beginning, but only created when they are called

1.3.4 Class template object as function parameter

 

learning target:

  • Objects instantiated from class templates, how to pass parameters to functions

There are three input methods:

  1. Specify the incoming type --- directly display the data type of the object

  2. Parameter templating --- Turn the parameters in the object into templates for passing

  3. The entire class is templated --- Template the object type for passing

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 more widely used is the first one: specify the incoming type

 

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 the 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 objective: to be able to master the implementation of member functions in class templates outside the class

 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 a member function in a class template is implemented outside the class, a template parameter list needs to be added

1.3.7 Class Template File Compilation

learning target:

  • Master the problems and solutions caused by the division of files into class template member functions

question:

  • The creation time of the member function in the class template is in the call phase, resulting in the failure to link when writing the sub-file

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 the agreed name, 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;
}

Write the code in .cpp by dividing the class template into files

#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, 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

Implementation of global functions within the class - just declare friends directly within the class

Out-of-class implementation of global functions - need to let the compiler know the existence of global functions 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 the global function be implemented in the class, the usage is simple, and the compiler can directly recognize it

 

1.3.9 Class template example

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

  • Data of built-in data types and custom data types can be stored

  • Store the data in the array to the heap

  • The capacity of the array that can be passed in to the constructor

  • Provide corresponding copy constructor and operator= to prevent shallow copy problems

  • Provide tail insertion and tail deletion methods to add and delete data in the array

  • The elements in the array can be accessed by subscripting

  • 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 realize general-purpose arrays

 

2 Introduction to STL

2.1 The birth of STL

  • The software world has long wanted to build something reusable

  • C++'s object-oriented and generic programming ideas aim to improve reusability

  • In most cases, there is no standard for data structures and algorithms, resulting in a lot of repetitive 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)

  • There is a seamless connection between the container and the algorithm through an iterator .

  • Almost all code in STL uses template classes or template functions

2.3 Six components of STL

STL is roughly divided into six major components, namely: container, algorithm, iterator, functor, adapter (adapter), 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 some kind of strategy for an algorithm.

  5. Adapter: A thing used to decorate a container or a functor or iterator interface.

  6. Space configurator: Responsible for space configuration and management.

 

2.4 Containers, Algorithms, Iterators in STL

Container: a place for storage

The STL container is to realize some of the most widely used data structures

Commonly used data structures: arrays, linked lists, trees, stacks, queues, collections, mapping tables, etc.

These containers are divided into two types : sequential containers and associative containers :

Sequential container : Emphasizes the sorting of values, and 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 to solve logical or mathematical problems, this subject we call algorithms (Algorithms)

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

Qualitative change algorithm: It means that the content of the elements in the interval will be changed during the operation. such as copy, replace, delete, etc.

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

Iterators: the glue between containers and algorithms

Provides a method that enables sequential access to 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. At the beginning stage, we can first understand that iterators are pointers

Iterator type:

type Function Support operation
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 Read and write, support ++, ==,! =
bidirectional iterator Read and write operations, and can operate forward and backward Read and write, support ++, --,
random access iterator Read and write operations, can access arbitrary data in a jumping way, the most powerful iterator Read and write, support ++, --, [n], -n, <, <=, >, >=

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

2.5 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. Next, 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

iterators: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 objective: store custom data types in vector and print out

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 objective: Containers are nested in containers, we will traverse all data and output

Example:  

#include <vector>

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

	vector< vector<int> >  v;

	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	vector<int> v4;

	for (int i = 0; i < 4; i++) {
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
		v4.push_back(i + 4);
	}

	//将容器元素插入到vector v中
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);


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

}

int main() {

	test01();

	system("pause");

	return 0;
}

3 STL-Common container

3.1 string container

3.1.1 Basic concept 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, and manages this string, which is a container of char* type.

Features:

The string class internally encapsulates many member methods

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

String manages the memory allocated by char*, so you don’t have to worry about copying out of bounds and value out of bounds, etc., and the class is responsible for it

3.1.2 String constructor

Constructor prototype:

  • string();//Create an empty string such as: string str;

  • string(const char* s);//Initialize with string s

  • string(const string& str);//Use a 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 multiple construction methods of string are not comparable, just use them flexibly

3.1.3 String assignment operation

Function description:

  • assign value to string string

The function prototype of the assignment:

  • string& operator=(const char* s);//Char* type string is assigned to the current string

  • string& operator=(const string &s);//Assign the string s to the current string

  • string& operator=(char c);//Character assignment to the current string

  • string& assign(const char *s);//Assign the string s to the current string

  • string& assign(const char *s, int n);//Assign the first n characters of the string s to the current string

  • string& assign(const string &s);//Assign the 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 assignment methods of string, operator=this method is more practical

 

3.1.4 String concatenation

Function description:

  • Realize splicing strings at the end of strings

Function prototype:

  • string& operator+=(const char* str);// Overload += operator

  • string& operator+=(const char c);// Overload += operator

  • string& operator+=(const string& str);// Overload += operator

  • string& append(const char *s);//Connect the string s to the end of the current string

  • string& append(const char *s, int n);//Connect the first n characters of the 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 the 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 splicing, just remember a few at the beginner 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 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 the string str

  • string& replace(int pos, int n,const char* s);//Replace the n characters starting from pos with the 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");//从1号位置其将三个字符替换为1111

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

int main() {

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

	system("pause");

	return 0;
}

Summarize:

  • find searches from left to back, rfind from right to left

  • find returns the position of the first character found after finding the string, and returns -1 if not found

  • When replacing, you need to specify from which position, how many characters, and what kind of string to replace

 

3.1.6 string string comparison

Function description:

  • comparison between strings

Compare by:

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

= returns 0

> return 1

< returns -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, and it is not very meaningful to judge who is bigger and who 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 by []

  • char& at(int n);/ / Get the character through the at method

Example:  

void test01()
{
	string str = "hello world";

	for (int i = 0; i < str.size(); i++)//size返回长度
	{
		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, using [ ] or at

3.1.8 string insertion and deletion

Function description:

  • Insert and delete characters on the string string

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;//Returns 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 concept 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 the array is a static space, and the vector can be dynamically expanded

Dynamic expansion:

  • It is not to continue the new space after the original space, but to find a larger memory space, and then copy the original data to the new space to release the original space

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

3.2.2 vector构造函数

功能描述:

  • 创建vector容器

函数原型:

  • vector<T> v; //采用模板实现类实现,默认构造函数

  • vector(v.begin(), v.end()); //将v[begin(), end())区间中的元素拷贝给本身。

  • vector(n, elem); //构造函数将n个elem拷贝给本身。

  • vector(const vector &vec); //拷贝构造函数。

示例:  

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

总结:vector的多种构造方式没有可比性,灵活使用即可

3.2.3 vector赋值操作

功能描述:

  • 给vector容器进行赋值

函数原型:

  • vector& operator=(const vector &vec);//重载等号操作符

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

 示例:

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

总结: vector赋值方式比较简单,使用operator=,或者assign都可以

3.2.4 vector容量和大小

功能描述:

  • 对vector容器的容量和大小操作

函数原型:

  • empty(); //判断容器是否为空

  • capacity(); //容器的容量

  • size(); //返回容器中元素的个数

  • resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

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

  • resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

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

 示例:

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

总结:

  • 判断是否为空 --- empty

  • 返回元素个数 --- size

  • 返回容器容量 --- capacity

  • 重新指定大小 --- resize

3.2.5 vector插入和删除

功能描述:

  • 对vector容器进行插入、删除操作

函数原型:

  • push_back(ele); //尾部插入元素ele

  • pop_back(); //删除最后一个元素

  • insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele

  • insert(const_iterator pos, int count,ele);//迭代器指向位置pos插入count个元素ele

  • erase(const_iterator pos); //删除迭代器指向的元素

  • erase(const_iterator start, const_iterator end);//删除迭代器从start到end之间的元素

  • clear(); //删除容器中所有元素

示例:  


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

总结:

  • 尾插 --- push_back

  • 尾删 --- pop_back

  • 插入 --- insert (位置迭代器)

  • 删除 --- erase (位置迭代器)

  • 清空 --- clear

3.2.6 vector数据存取

功能描述:

  • 对vector中的数据的存取操作

函数原型:

  • at(int idx); //返回索引idx所指的数据

  • operator[]; //返回索引idx所指的数据

  • front(); //返回容器中第一个数据元素

  • back();//returns 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 get elements in the vector container, [ ] and at can also

  • front returns the first element of the container

  • back returns the last element of the container

3.2.7 vector swap container

Function description:

  • To achieve the exchange of elements in two containers

Function prototype:

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

 Example:

#include <vector>

void printVector(vector<int>& v) {

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

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

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

	//互换容器
	cout << "互换后" << endl;
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}
//实际用途
//巧用swap可以收缩内存空间
void test02()
{
	vector<int> v;
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
	}

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

	v.resize(3);

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

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

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

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

Summary: swap can make two containers interchangeable, which can achieve a practical effect of shrinking memory

3.2.8 vector reserved space

Function description:

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

Function prototype:

  • reserve(int len);//The container reserves len element length, the reserved position is not initialized, and the element is 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 concept of deque container

Function:

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

The difference between deque and vector:

  • The insertion and deletion efficiency of vector for the head is low, and the larger the data volume, the lower the efficiency

  • Relatively speaking, deque inserts and deletes the head faster than vector

  • Vector accesses elements faster than deque, which is related to the internal implementation of the two

The inner working principle of deque:

There is a central controller inside the deque , which maintains the contents of each buffer, and stores real data in the buffer

The central controller maintains the address of each buffer, making deque like a continuous memory space

  • 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 the deque container and the vector container are almost the same, and they can be used flexibly

3.3.3 deque assignment operation

Function description:

  • Assign a value to the deque container

Function prototype:

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

  • assign(beg, end);//Assign the copy of the data in the interval [beg, end) 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

3.3.4 Deque size operation

Function description:

  • Operate on the size of the deque container

Function prototype:

  • deque.empty();// Check if the container is empty

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

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

                                     // If the container gets shorter, elements at the end that exceed the length of the container are removed.

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

                                            // If the container gets shorter, elements at the end that exceed the length of the container are removed.

 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

  • Return the number of elements --- size

  • Re-specify the number --- resize

3.3.5 deque insertion and deletion

Function description:

  • Insert and delete data into the deque container

Function prototype:

Insert operation at both ends:

  • push_back(elem);//Add a data at the end of the container

  • push_front(elem);//Insert a data at the head of the container

  • pop_back();//Delete the last data in the container

  • pop_front();//Delete the first data in the container

Specified position operation:

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

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

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

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

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

  • erase(pos);//Delete the data at position pos 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 plug --- push_back

  • Tail delete --- pop_back

  • Head plug --- push_front

  • Head delete --- pop_front

3.3.6 deque data access

Function description:

  • Access to data in deque

Function prototype:

  • at(int idx);//Return the data pointed to by the index idx

  • operator[];//Return the data pointed to by the index idx

  • front();//returns the first data element in the container

  • back();//returns 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 get elements in the deque container, [ ] and at can also

  • front returns the first element of the container

  • back returns the last element of the container

3.3.7 deque sorting

Function description:

  • Using algorithms to sort deque containers

algorithm:

  • sort(iterator beg, iterator end)//Sort the elements in the beg and end intervals, the default ascending order

For containers that support random access iterators, the sort algorithm can be used to directly sort them. 

Vector containers can also be sorted using sort

 Example:

#include <deque>
#include <algorithm>

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

	}
	cout << endl;
}

void test01()
{

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

	printDeque(d);
	sort(d.begin(), d.end());
	printDeque(d);

}

int main() {

	test01();

	system("pause");

	return 0;
}

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: contestant ABCDE, 10 judges score each contestant separately, remove the highest score, remove the lowest score among the judges, and take the average score.

3.4.2 Implementation steps

  1. Create five players and put them in the vector

  2. Traverse the vector container, take out each player, execute the for loop, and save 10 ratings in the deque container

  3. The sort algorithm sorts the scores in the deque container, removing the highest and lowest scores

  4. The deque container traverses once, accumulating the total score

  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 containers to operate data can improve the efficiency of the code

3.5 stack container

3.5.1 Basic concept of stack

Concept: stack is a first-in-last-out (FILO) data structure, which has only one exit

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

Entering data in the stack is called --- stacking push

Popping data from the stack is called --- popping the stack pop

Stacks in life:  

 

 

3.5.2 Stack common interface

Function description: Commonly used external interfaces of stack containers

Constructor:

  • stack<T> stk;//stack is implemented using a template class, and the default construction form of the stack object

  • stack(const stack &stk);//copy constructor

Assignment operation:

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

Data access:

  • push(elem);// add an element to the top of the stack

  • pop();//Remove the first element from the top of the stack

  • top();// return the top element of the stack

Size operation:

  • empty();// Check if the stack is empty

  • size();// return the size of the stack

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:

  • Into the stack --- push

  • Pop out --- 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 concept of queue

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

The 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 in the queue is called --- entering the queue push

The data out of the queue is called --- out of the queue pop

Queue in life:  

3.6.2 Queue common interface

Function description: Commonly used external interfaces of stack containers

Constructor:

  • queue<T> que;//queue is implemented by a template class, and the default construction form of the queue object

  • queue(const queue &que);//copy constructor

Assignment operation:

  • queue& operator=(const queue &que);// Overload the equals 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

Size operation:

  • empty();// Check if the stack is empty

  • size();// return the size of the stack

 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

  • Return the head element --- front

  • Return the element at the end of the queue --- back

  • Determine whether the team is empty --- empty

  • return queue size --- size

3.7 list container

3.7.1 Basic concept of list

Function: chain storage of data

A linked list (list) is a discontinuous storage structure on a physical storage unit, and the logical order of data elements is realized through pointer links in the linked list

The composition of the linked list: the linked list is composed of a series of nodes

The composition of the node: one is a data field that stores data elements, and the other is a pointer field that stores the address of the next node

The linked list in STL is a doubly circular linked list

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

Advantages of lists:

  • Using dynamic storage allocation, will not cause memory waste and overflow

  • The linked list is very convenient to perform insertion and deletion operations, just modify the pointer without moving a large number of elements

Disadvantages of lists:

  • The linked list is flexible, but the space (pointer field) and time (traversal) are extra expensive

List has an important property, the insertion and deletion operations will not invalidate the original list iterator, which is not true in 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;//list is implemented using a template class, and the default construction form of the object:

  • 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 construction method of list is the same as that of several other STL commonly used containers, just be familiar with it

3.7.3 list assignment and exchange

Function description:

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

Function prototype:

  • assign(beg, end);//Assign the copy of the data in the interval [beg, end) to itself.

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

  • list& operator=(const list &lst);// Overload the equals operator

  • swap(lst);//Swap 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 on the size of the list container

Function prototype:

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

  • empty();// Check if the container is empty

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

                          // If the container gets shorter, elements at the end that exceed the length of the container are removed.

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

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

 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

  • Return the number of elements --- size

  • Re-specify the number --- resize

3.7.5 list insertion and deletion

Function description:

  • Insert and delete data to the list container

Function prototype:

  • push_back(elem);//Add an element at 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 position pos, no return value.

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

  • clear();//Remove all data in 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 plug --- push_back

  • Tail delete --- pop_back

  • Head plug --- push_front

  • Head delete --- pop_front

  • insert --- insert

  • delete --- erase

  • remove --- remove

  • Empty --- clear

 

3.7.6 list data access

Function description:

  • Access the 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--;//支持双向
	//it = it + 1;//错误,不可以跳跃访问,即使是+1
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summarize:

  • Data cannot be accessed through [] or at in the list container

  • return the first element --- front

  • Return the last element --- back

 

3.7.7 List inversion and sorting

Function description:

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

All containers that do not support random access iterators cannot use the standard algorithm sort()

Containers that do not support random access iterators, internally provide some corresponding algorithms L.sort()

Function prototype:

  • reverse();// reverse linked list

  • sort();//List sort

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

	//排序
    //所有不支持随机访问迭代器的容器,不可以用标准算法  sort()
    //不支持随机访问迭代器的容器,内部会提供对应一些算法  L.sort()
	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 case

Case description: Sort the custom data types of Person, and the attributes in Person include name, age, and height

Sorting rules: ascending order by age, descending order by height if the 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 does not know how to sort

  • Advanced sorting is just another logical rule formulation on the sorting rules, which is not complicated

 

3.8 set/ multiset containers

3.8.1 Basic concept of set

Introduction:

  • All elements are automatically sorted on insertion

Nature:

  • set/multiset is an associative container , and the underlying structure is implemented with 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 equals 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 sorted automatically

3.8.3 Set size and swap

Function description:

  • Statistics set container size and exchange set container

Function prototype:

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

  • empty();// Check if 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 an element into the container.

  • clear();//clear all elements

  • erase(pos);//Delete the element pointed 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

  • Empty --- clear

3.8.5 set search and statistics

Function description:

  • Find data and statistics on the set container

Function prototype:

  • find(key);//Find 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 in the 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 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 will 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 you are not allowed to insert duplicate data, you can use set

  • If you need to insert duplicate data use multiset

3.8.7 Create a pair

Function description:

  • Data that appears in pairs, using pairs can 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:

You can create a pair in both ways, just remember one

 

3.8.8 Set container sorting

learning target:

  • The default sorting rule of the set container is from small to large, master how to change the sorting rule

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 the functor 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 to insert data

 

3.9 map/multimap container

3.9.1 Basic concept of map

Introduction:

  • All elements in the map are pairs

  • The first element in the pair is key (key value), which acts as an index, and the second element is value (real value)

  • All elements are automatically sorted according to the key value of the element

Nature:

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

advantage:

  • The value can be quickly found according to 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 equals 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 are used when inserting data

 

3.9.3 Map size and swapping

Function description:

  • Statistics map container size and exchange map container

Function prototype:

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

  • empty();// Check if 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:

  • The map container inserts data and deletes data

Function prototype:

  • insert(elem);// Insert an element into the container.

  • clear();//clear all elements

  • erase(pos);//Delete the element pointed 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

  • Empty --- clear

3.9.5 Map search and statistics

Function description:

  • Find data and statistics on the map container

Function prototype:

  • find(key);//Find 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 in the 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, master how to change the sorting rule

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 the functor to specify the sorting rules of the map container

  • For custom data types, map must specify sorting rules, same as set container

3.10 Case - Employee Grouping

3.10.1 Case description

  • The company recruited 10 employees (ABCDEFGHIJ) today. After 10 employees enter the company, they need to be assigned to work in that department

  • Employee information includes: name and salary; 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 perform random grouping

  3. After grouping, use the employee's 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 the data exists in the form of key-value pairs, you can consider using map or multimap

 

4 STL-Function Objects

4.1 Function objects

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 Function Object Usage

Features:

  • When a function object is used, it can be called like a normal function, it can have parameters, and it can have a return value

  • Function objects go beyond the concept of ordinary functions, and function objects can have their own state

  • Function objects can be passed as arguments

Example:

#include <string>
​
//1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
class MyAdd
{
public :
    int operator()(int v1,int v2)
    {
        return v1 + v2;
    }
};
​
void test01()
{
    MyAdd myAdd;
    cout << myAdd(10, 10) << endl;
}
​
//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:

  • Functors are very flexible and can be passed as parameters.

4.2 Predicates

4.2.1 Predicate concept

concept:

  • Functors that return bool type are called predicates

  • If operator() takes one argument, it is called a unary predicate

  • If operator() takes two arguments, it is called a binary predicate

4.2.2 Unary predicates

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 predicates

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 The meaning of built-in function object

concept:

  • The STL has some built-in function objects

Classification:

  • arithmetic functor

  • relational functor

  • logical functor

usage:

  • The objects generated by these functors are used in exactly the same way as ordinary functions

  • To use the built-in function object, you need to import the header file#include<functional>

4.3.2 Arithmetic functors

Function description:

  • Realize the four 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>//Take the imitation function

  • template<class T> T negate<T>// take inverse functor

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 relational 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 NOT

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: There are few practical applications of logic functors, just understand

 

 

5 STL-Common Algorithms

Overview :

  • Algorithms are mainly composed of header files <algorithm> <functional> <numeric>.

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

  • <numeric>Small in size, only includes a few template functions to perform simple mathematical operations on sequences

  • <functional>Some template classes are defined for declaring function objects.

5.1 Commonly used traversal algorithms

learning target:

  • Master common 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 container

Function prototype:

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

    // The traversal algorithm traverses the container elements

    // beg starts the iterator

    // end end 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 needs to be mastered

5.1.2 transform

Function description:

  • Move a container to another container

Function prototype:

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

//beg1 source container start iterator

//end1 source container end iterator

//beg2 target container start 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 to be transported 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 element by condition

  • adjacent_find// find adjacent duplicate elements

  • binary_search// binary search method

  • count// Count the number of elements

  • count_if// Count the number of elements by condition

5.2.1 find

Function description:

  • Find the specified element, find the iterator that returns the specified element, if not found, return the end iterator end()

Function prototype:

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

    // Find the element by value, if found, return the iterator at the specified position, if not found, return the end iterator position

    // beg starts the iterator

    // end end iterator

    // The element that value is looking for

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 element by condition

Function prototype:

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

    // Find the element by value, if found, return the iterator at the specified position, if not found, return the end iterator position

    // beg starts the iterator

    // end end iterator

    // _Pred function or predicate (function function returning bool type)

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 finds by condition to make the search more flexible, and the functor provided 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 repeated elements and return an iterator to the first position of the adjacent element

    // beg starts the iterator

    // end end 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 find adjacent repeated elements in the interview question, remember to use the adjacent_find algorithm in STL

Function description:

  • Find if the specified element exists

Function prototype:

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

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

    // note: not available in unordered sequences

    // beg starts the iterator

    // end end iterator

    // The element that value is looking for

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 searched container must have 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 the element

    // beg starts the iterator

    // end end iterator

    // elements of value 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 by condition

Function prototype:

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

    // Count the number of occurrences of elements by condition

    // beg starts the iterator

    // end end 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: count by value and count_if by condition

5.3 Common sorting algorithms

learning target:

  • Master common sorting algorithms

Algorithm introduction:

  • sort//Sort the elements in the container

  • random_shuffle//Shuffle the elements in the specified range to randomly adjust the order

  • merge// The container elements are merged and stored in another container

  • reverse// Reverse the specified range of elements

5.3.1 sort

Function description:

  • Sort the elements in the container

Function prototype:

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

    // Find the element by value, if found, return the iterator at the specified position, if not found, return the end iterator position

    // beg starts the iterator

    // end end 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 needs to be mastered

5.3.2 random_shuffle

Function description:

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

Function prototype:

  • random_shuffle(iterator beg, iterator end);

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

    // beg starts the iterator

    // end end iterator

Example:

#include <algorithm>
#include <vector>
#include <ctime>
​
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
​
void test01()
{
    srand((unsigned int)time(NULL));
    vector<int> v;
    for(int i = 0 ; i < 10;i++)
    {
        v.push_back(i);
    }
    for_each(v.begin(), v.end(), myPrint());
    cout << endl;
​
    //打乱顺序
    random_shuffle(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint());
    cout << endl;
}
​
int main() {
​
    test01();
​
    system("pause");
​
    return 0;
}

Summary: The random_shuffle shuffling algorithm is more practical, remember to add random number seeds when using it

5.3.3 merge

Function description:

  • The two container elements are merged and stored in another container

Function prototype:

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

    // The container elements are merged and stored in another container

    // Note: the two containers must be in order

    // beg1 container 1 start iterator // end1 container 1 end iterator // beg2 container 2 start iterator // end2 container 2 end iterator // dest destination container start iterator

Example:

#include <algorithm>
#include <vector>
​
class myPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
​
void test01()
{
    vector<int> v1;
    vector<int> v2;
    for (int i = 0; i < 10 ; i++) 
    {
        v1.push_back(i);
        v2.push_back(i + 1);
    }
​
    vector<int> vtarget;
    //目标容器需要提前开辟空间
    vtarget.resize(v1.size() + v2.size());
    //合并  需要两个有序序列
    merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());
    for_each(vtarget.begin(), vtarget.end(), myPrint());
    cout << endl;
}
​
int main() {
​
    test01();
​
    system("pause");
​
    return 0;
}

Summary: The ordered sequence of the two containers merged by merge

5.3.4 reverse

Function description:

  • Reverse the elements in the container

Function prototype:

  • reverse(iterator beg, iterator end);

    // Reverse the specified range of elements

    // beg starts the iterator

    // end end 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, interview questions may involve

5.4 Common Copy and Replace Algorithms

learning target:

  • Master common copy and replace algorithms

Algorithm introduction:

  • copy// Copy the elements of the specified range in the container to another container

  • replace// Modify the old elements in the specified range in the container to new elements

  • replace_if// Elements in the specified range in the container that meet the conditions are replaced with new elements

  • swap// Swap the elements of the two containers

5.4.1 copy

Function description:

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

Function prototype:

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

    // Find the element by value, if found, return the iterator at the specified position, if not found, return the end iterator position

    // beg starts the iterator

    // end end 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, the target container remembers to open up space in advance

5.4.2 replace

Function description:

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

Function prototype:

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

    // Replace the old elements in the interval with new elements

    // beg starts the iterator

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

5.4.3 replace_if

Function description:

  • Replace the elements in the interval that meet the conditions with the specified elements

Function prototype:

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

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

    // beg starts the iterator

    // end end iterator

    // _pred predicate

    // The new element replaced by newvalue

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 by conditions, and you can use the functor to flexibly filter the conditions that meet

5.4.4 swap

Function description:

  • Swaps 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, note that the swapped containers must be of the same type

5.5 Common Arithmetic Generation Algorithms

learning target:

  • Master commonly used 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 the container elements

  • fill// add elements to the container

5.5.1 accumulate

Function description:

  • Computes the cumulative sum of the container elements in the range

Function prototype:

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

    // Calculate the cumulative sum of the container elements

    // beg starts the iterator

    // end end iterator

    // value start 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: Note that the header file is numeric when using accumulate, 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 end 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 interval with the specified value

5.6 Common Set Algorithms

learning target:

  • Master commonly used 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 of 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 collections must be ordered sequences

    // beg1 container 1 start iterator // end1 container 1 end iterator // beg2 container 2 start iterator // end2 container 2 end iterator // dest destination container start iterator

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:

  • the ordered sequence necessary for the intersection of two sets

  • The target container needs to take the small 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 collections must be ordered sequences

    // beg1 container 1 start iterator // end1 container 1 end iterator // beg2 container 2 start iterator // end2 container 2 end iterator // dest destination container start iterator

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:

  • The ordered sequence necessary to find the union of two sets

  • The target container needs to add 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 of two sets

Function prototype:

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

    // Find the difference of two sets

    // Note: The two collections must be ordered sequences

    // beg1 container 1 start iterator // end1 container 1 end iterator // beg2 container 2 start iterator // end2 container 2 end iterator // dest destination container start iterator

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:

  • The ordered sequence necessary for two sets to be subtracted

  • 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/weixin_58176527/article/details/127792859