Dark horse programmer / C + + improve programming handout

=Generic programming and STL = = technology are explained in detail to explore the deeper use of C + +

1 template

1.1 concept of template

Template is to establish a general mold, which greatly improves the reusability

Characteristics of formwork:

  • The template cannot be used directly. It is just a framework
  • The universality of templates is not everything

1.2 function template

  • Another programming idea of C + + is called generic programming, which mainly uses template technology

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

1.2.1 function template syntax

Function template function:

Establish a general function whose function return value type and formal parameter type can be represented by a virtual type without specific formulation.

Syntax:

template<typename T>
Function declaration or definition

Explanation:

Template - declare to create a template

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

T-A common data type whose name can be replaced, usually in uppercase letters

Example:

//Commutative integer function
void swapInt(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

//Swap floating point functions
void swapDouble(double& a, double& b) {
	double temp = a;
	a = b;
	b = temp;
}

//Using templates to provide general exchange functions
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);

	//Exchange using template
	//1. Automatic type derivation
	mySwap(a, b);

	//2. Displays the specified type
	mySwap<int>(a, b);

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

}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

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

1.2.2 precautions for function template

matters needing attention:

  • For automatic type derivation, a consistent data type T must be derived before it can be used

  • The template can be used only after the data type of T is determined

Example:

//Using templates to provide general exchange functions
template<class T>
void mySwap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}


// 1. For automatic type derivation, a consistent data type T must be derived before it can be used
void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';

	mySwap(a, b); // Correct, a consistent T can be derived
	//mySwap(a, c); //  Error, unable to deduce a consistent T type
}


// 2. The template can be used only after the data type of T is determined
template<class T>
void func()
{
	cout << "func call" << endl;
}

void test02()
{
	//func(); // Error: the template cannot be used independently. The type of T must be determined
	func<int>(); //The template can be used only after T is given a type by displaying the specified type
}

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

Summary:

  • When using the template, the general data type T must be determined and the consistent type can be deduced

1.2.3 function template cases

Case description:

  • Using the function template to encapsulate a sorting function, you can sort arrays of different data types
  • The sorting rules are from large to small, and the sorting algorithm is selective sorting
  • Test with char array and int array respectively

Example:

//Exchanged function templates
template<typename T>
void mySwap(T &a, T&b)
{
	T temp = a;
	a = b;
	b = temp;
}


template<class T> // You can also replace it with typename
//Select sorting is used to sort the array from large to small
void mySort(T arr[], int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i; //Subscript of maximum number
		for (int j = i + 1; j < len; j++)
		{
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		if (max != i) //If the subscript of the maximum number is not i, swap the two
		{
			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()
{
	//Test char array
	char charArr[] = "bdcfeagh";
	int num = sizeof(charArr) / sizeof(char);
	mySort(charArr, num);
	printArray(charArr, num);
}

void test02()
{
	//Test int array
	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;
}

Conclusion: template can improve code reuse, which needs to be mastered skillfully

1.2.4 differences between ordinary functions and function templates

Differences between ordinary functions and function templates:

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

Example:

//Ordinary function
int myAdd01(int a, int b)
{
	return a + b;
}

//Function template
template<class T>
T myAdd02(T a, T b)  
{
	return a + b;
}

//When using function templates, if automatic type derivation is used, automatic type conversion will not occur, that is, implicit type conversion
void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	
	cout << myAdd01(a, c) << endl; //Correct, implicitly convert 'c' of char type to ASCII code 99 corresponding to int type 'c'

	//myAdd02(a, c); //  An error is reported. When automatic type derivation is used, implicit type conversion will not occur

	myAdd02<int>(a, c); //Correct, if you specify the type with display, implicit type conversion can occur
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: it is recommended to call the function template by displaying the specified type, because you can determine the general type T yourself

1.2.5 call rules for ordinary functions and function templates

The calling rules are as follows:

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

Example:

//General function and function template calling rules
void myPrint(int a, int b)
{
	cout << "Ordinary functions called" << endl;
}

template<typename T>
void myPrint(T a, T b) 
{ 
	cout << "Called template" << endl;
}

template<typename T>
void myPrint(T a, T b, T c) 
{ 
	cout << "Call overloaded template" << endl; 
}

void test01()
{
	//1. If both function templates and ordinary functions can be implemented, ordinary functions will be called first
	// Note that if you tell the compiler that there are ordinary functions, but only declare that they are not implemented or not implemented in the current file, you will report an error and cannot find them
	int a = 10;
	int b = 20;
	myPrint(a, b); //Call normal function

	//2. You can force a function template to be called through an empty template parameter list
	myPrint<>(a, b); //Calling function template

	//3. Function templates can also be overloaded
	int c = 30;
	myPrint(a, b, c); //Call overloaded function template

	//4. If the function template can produce a better match, call the function template first
	char c1 = 'a';
	char c2 = 'b';
	myPrint(c1, c2); //Calling function template
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: since the function template is provided, it is better not to provide ordinary functions, otherwise ambiguity is likely to occur

1.2.6 limitations of formwork

limitations:

  • The versatility of templates 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 implemented if the passed in a and b are an array

Another example:

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

In the above code, if the data type of T is a user-defined data type such as Person, it will not work normally

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

//Common function template
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}


//Materialize, display the materialized prototype and definition, start with template < >, and indicate the type by name
//Concretization takes precedence over regular templates
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;
	//The built-in data type can directly use the general function template
	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);
	//User defined data types do not call normal function templates
	//You can create a template of materialized Person data type for special processing of this type
	bool ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "p1 == p2 " << endl;
	}
	else
	{
		cout << "p1 != p2 " << endl;
	}
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

Summary:

  • The generalization of user-defined types can be solved by using specific templates
  • Learning templates is not to write templates, but to use the templates provided by the system in STL

Type 1.3 formwork

1.3.1 class template syntax

Class template function:

  • Establish a general class. The member data types in the class can be represented by a virtual type without specific formulation.

Syntax:

template<typename T>
class

Explanation:

Template - declare to create a template

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

T-A common data type whose name can be replaced, usually in uppercase letters

Example:

#include <string>
//Class template
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()
{
	// Specify NameType as string type and AgeType as int type
	Person<string, int>P1("Sun WuKong", 999);
	P1.showPerson();
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: the syntax of class template is similar to that of function template. Add class after declaration template, which is called class template

1.3.2 difference between class template and function template

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

  1. Class templates do not use automatic type derivation
  2. Class templates can have default parameters in the template parameter list

Example:

#include <string>
//Class template
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. Class templates do not use automatic type derivation
void test01()
{
	// Person p("Monkey King", 1000)// Automatic type derivation is not allowed when error class templates are used
	Person <string ,int>p("Sun WuKong", 1000); //The class template must be used in a way that displays the specified type
	p.showPerson();
}

//2. Class templates can have default parameters in the template parameter list
void test02()
{
	Person <string> p("Zhu Bajie", 999); //The template parameter list in the class template can specify default parameters
	p.showPerson();
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

Summary:

  • Class templates can only be used by displaying the specified type
  • The template parameter list in the class template can have default parameters

1.3.3 creation time of member function in class template

The creation timing of member functions in class templates is different from that in ordinary classes:

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

Example:

class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show" << endl;
	}
};

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

template<class T>
class MyClass
{
public:
	T obj;

	//The member functions in the class template are not created at the beginning, but are generated when the template is called

	void fun1() { obj.showPerson1(); }
	void fun2() { obj.showPerson2(); }

};

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

	//m.fun2();// There will be an error in compilation, which means that the function call will create the member function
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: the member functions in the class template are not created at the beginning, but only when called

1.3.4 function parameters of class template objects

Learning objectives:

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

There are three incoming methods:

  1. Specify the type of incoming - displays the data type of the object directly
  2. Parameter templating - changes parameters in an object into templates for transfer
  3. Whole class templating - pass this object type templating

Example:

#include <string>
//Class template
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. Specify the type of incoming
void printPerson1(Person<string, int> &p) 
{
	p.showPerson();
}
void test01()
{
	Person <string, int >p("Sun WuKong", 100);
	printPerson1(p);
}

//2. Parameter Templating
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{
	p.showPerson();
	cout << "T1 The types of are: " << typeid(T1).name() << endl;
	cout << "T2 The types of are: " << typeid(T2).name() << endl;
}
void test02()
{
	Person <string, int >p("Zhu Bajie", 90);
	printPerson2(p);
}

//3. Whole class Templating
template<class T>
void printPerson3(T & p)
{
	cout << "T The types of are: " << typeid(T).name() << endl;
	p.showPerson();

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

int main() {

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

	system("pause");

	return 0;
}

Summary:

  • There are three ways to pass parameters to functions for objects created through class templates
  • The first one is widely used: specify the type of incoming

1.3.5 class template and inheritance

When the class template encounters inheritance, you should pay attention to the following points:

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

Example:

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

//class Son:public Base / / error: memory needs to be allocated to subclasses for c + + compilation. You must know the type of T in the parent class before you can inherit downward
class Son :public Base<int> //You must specify a type
{
};
void test01()
{
	Son c;
}

//The class template inherits the class template. You can use T2 to specify the T type in the parent class
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 child class needs to specify the data type of T in the parent class

1.3.6 implementation outside class of class template member function

Learning objectives: be able to master the implementation of member functions outside the class in the class template

Example:

#include <string>

//Implementation outside class of member function in class template
template<class T1, class T2>
class Person {
public:
	//Member function class declaration
	Person(T1 name, T2 age);
	void showPerson();

public:
	T1 m_Name;
	T2 m_Age;
};

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

//Out of class implementation of member function
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
	cout << "full name: " << this->m_Name << " Age:" << this->m_Age << endl;
}

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

int main() {

	test01();

	system("pause");

	return 0;
}

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

1.3.7 preparation of class template by document

Learning objectives:

  • Master the problems and solutions arising from the preparation of class template member function sub files

Question:

  • The creation time of the member function in the class template is in the calling stage, which leads to the link failure when writing the sub file

solve:

  • Solution 1: include directly cpp source file
  • Solution 2: write the declaration and implementation to the same file and change the suffix to hpp, hpp is the agreed name, not mandatory

Example:

person. Code in 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;
};

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

//Out of class implementation of member function
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
	cout << "full name: " << this->m_Name << " Age:" << this->m_Age << endl;
}

Class templates are written in files Code in cpp

#include<iostream>
using namespace std;

//#include "person.h"
#include "person.cpp" / / solution 1: include the cpp source file

//Solution 2: write the declaration and implementation together, and change the file suffix to hpp
#include "person.hpp"
void test01()
{
	Person<string, int> p("Tom", 10);
	p.showPerson();
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: the second solution is to write the class template member functions together and change the suffix to hpp

1.3.8 class templates and friends

Learning objectives:

  • Master the in class and out of class implementation of class template and friend function

Implementation of global function in class - just declare friends directly in class

Out of class implementation of global functions - you need to let the compiler know the existence of global functions in advance

Example:

#include <string>

//2. The global function is implemented outside the friend class - first make the function template declaration, and then make the function template definition, and then make the friend
template<class T1, class T2> class Person;

//If the function template is declared, you can write the implementation to the back, otherwise you need to write the implementation to the front of the class for the compiler to see in advance
//template<class T1, class T2> void printPerson2(Person<T1, T2> & p); 

template<class T1, class T2>
void printPerson2(Person<T1, T2> & p)
{
	cout << "Out of class implementation ---- full name: " << p.m_Name << " Age:" << p.m_Age << endl;
}

template<class T1, class T2>
class Person
{
	//1. Global functions are implemented within friend classes
	friend void printPerson(Person<T1, T2> & p)
	{
		cout << "full name: " << p.m_Name << " Age:" << p.m_Age << endl;
	}


	//The global function is implemented outside the friend class
	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. Global functions are implemented within classes
void test01()
{
	Person <string, int >p("Tom", 20);
	printPerson(p);
}


//2. Global functions are implemented outside the class
void test02()
{
	Person <string, int >p("Jerry", 30);
	printPerson2(p);
}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: it is recommended to implement the global function in class, which is simple to use and can be directly recognized by the compiler

1.3.9 type template cases

Case description: implement a general array class. The requirements are as follows:

  • Data of built-in data type and user-defined data type can be stored
  • Store the data in the array in the heap
  • The capacity of the array that can be passed in the constructor
  • Provide the corresponding copy constructor and operator = to prevent shallow copy problems
  • Tail interpolation and tail deletion methods are provided to add and delete data in the array
  • The elements in the array can be accessed by subscript
  • You can get the current number of elements in the array and the capacity of the array

Example:

myArray. Code in HPP

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

template<class T>
class MyArray
{
public:
    
	//Constructor
	MyArray(int capacity)
	{
		this->m_Capacity = capacity;
		this->m_Size = 0;
		pAddress = new T[this->m_Capacity];
	}

	//copy construction 
	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++)
		{
			//If T is an object and contains a pointer, the = operator must be overloaded, because the equal sign is not a construction but an assignment,
			// Ordinary types can be directly = but pointer types need deep copy
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	//Overload = operator prevents shallow copy problems
	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;
	}

	//Overload [] operator arr[0]
	T& operator [](int index)
	{
		return this->pAddress[index]; //Do not consider crossing the boundary, and the user will handle it by himself
	}

	//Tail interpolation
	void Push_back(const T & val)
	{
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;
		this->m_Size++;
	}

	//Tail deletion
	void Pop_back()
	{
		if (this->m_Size == 0)
		{
			return;
		}
		this->m_Size--;
	}

	//Get array capacity
	int getCapacity()
	{
		return this->m_Capacity;
	}

	//Get array size
	int	getSize()
	{
		return this->m_Size;
	}


	//Deconstruction
	~MyArray()
	{
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
	}

private:
	T * pAddress;  //Points to a heap space that stores real data
	int m_Capacity; //capacity
	int m_Size;   // size
};

Class template case - array class encapsulation In cpp

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

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

//Test built-in data types
void test01()
{
	MyArray<int> array1(10);
	for (int i = 0; i < 10; i++)
	{
		array1.Push_back(i);
	}
	cout << "array1 Printout:" << endl;
	printIntArray(array1);
	cout << "array1 Size of:" << array1.getSize() << endl;
	cout << "array1 Capacity:" << array1.getCapacity() << endl;

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

	MyArray<int> array2(array1);
	array2.Pop_back();
	cout << "array2 Printout:" << endl;
	printIntArray(array2);
	cout << "array2 Size of:" << array2.getSize() << endl;
	cout << "array2 Capacity:" << array2.getCapacity() << endl;
}

//Test custom data types
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 << "full name:" << personArr[i].m_Name << " Age: " << personArr[i].m_Age << endl;
	}

}

void test02()
{
	//Create array
	MyArray<Person> pArray(10);
	Person p1("Sun WuKong", 30);
	Person p2("Han Xin", 20);
	Person p3("Daji", 18);
	Person p4("Wang Zhaojun", 15);
	Person p5("Zhao Yun", 24);

	//insert data
	pArray.Push_back(p1);
	pArray.Push_back(p2);
	pArray.Push_back(p3);
	pArray.Push_back(p4);
	pArray.Push_back(p5);

	printPersonArray(pArray);

	cout << "pArray Size of:" << pArray.getSize() << endl;
	cout << "pArray Capacity:" << pArray.getCapacity() << endl;

}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary:

Be able to use the knowledge points learned to realize a general array

First knowledge STL

2.1 birth of STL

  • For a long time, the software industry has been hoping to build something that can be reused

  • The object-oriented and generic programming idea of C + + aims to improve the reusability

  • In most cases, data structures and algorithms fail to have a set of standards, resulting in being forced to do a lot of repetitive work

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

2.2 basic concepts of STL

  • STL(Standard Template Library)
  • STL is broadly divided into: container algorithm and iterator
  • Containers and algorithms are seamlessly connected through iterators.
  • Almost all STL codes use template classes or template functions

2.3 STL six components

STL is generally divided into six components: container, algorithm, iterator, imitation function, adapter (adapter) and space configurator

  1. Container: various data structures, such as vector, list, deque, set, map, etc., are used to store data.
  2. Algorithm: various commonly used algorithms, such as sort, find, copy and for_each et al
  3. Iterator: acts as the glue between the container and the algorithm.
  4. Imitation function: the behavior is similar to the function, which can be used as a strategy of the algorithm.
  5. Adapter: something used to decorate a container or an interface to an emulator or iterator.
  6. Space configurator: responsible for space configuration and management.

2.4 containers, algorithms and iterators in STL

**Container: * * place of storage

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

Common data structures: array, linked list, tree, stack, queue, set, mapping table, etc

These containers are divided into sequential containers and associated containers:

Sequential container: it emphasizes the sorting of values. Each element in the sequential container has a fixed position.
Associative container: a binary tree structure in which there is no strict physical order between the elements

**Algorithm: * * solution of the problem

Limited steps to solve logical or mathematical problems. This discipline is called algorithms

Algorithms are divided into: qualitative algorithm and non qualitative algorithm.

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

Non qualitative algorithm: it means that the element content in the interval will not be changed during the operation, such as searching, counting, traversing, searching for extreme values, etc

**Iterator: * * glue between container and algorithm

A method is provided to enable it to search the elements contained in a container in order without exposing the internal representation of the container.

Each container has its own iterator

The use of iterators is very similar to pointers. At the beginning of learning, we can understand that iterators are pointers

Iterator type:

typefunctionSupport operation
Input Iterator Read only access to dataRead only, support + +, = ==
output iterators Write only access to dataWrite only, support++
forward iterators Read and write operations, and can push the iterator forwardRead and write, support + +, = ==
Bidirectional Iterator Read and write operations, and can operate forward and backwardRead and write, support + +, –,
random access iterators Read and write operation, which can access any data in a jumping way. It is the most powerful iteratorRead and write, support + +, –, [n], - N, <, < =, >, >=

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

2.5 initial knowledge of container algorithm iterator

After understanding the concepts of container, algorithm and iterator in STL, we use the code to feel the charm of STL

The most commonly used container in STL is Vector, which can be understood as 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

Containers: vector

Algorithm: for_each

Iterator: vector < int >:: iterator

Example:

#include <vector>
#include <algorithm>

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

void test01() {

	//The data type in the container is specified by the parameter vector in the template
	vector<int> v;
	//Put data into container
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);

	//Each container has its own iterator, which is used to traverse the elements in the container
	//v.begin() returns an iterator that points to the first data in the container
	//v.end() returns an iterator that points to the next location of the last element of the container element
	//Vector < int >:: iterator gets the iterator type of the container vector < int >

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

	//The first traversal method:
	while (pBegin != pEnd) {
		cout << *pBegin << endl;
		pBegin++;
	}

	
	//The second traversal method:
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << endl;
	}
	cout << endl;

	//The third traversal method:
	//Use STL to provide standard traversal algorithm header file algorithm
	for_each(v.begin(), v.end(), MyPrint);
}

int main() {

	test01();

	system("pause");

	return 0;
}

2.5.2 Vector stores user-defined data types

Learning objectives: store user-defined data types in vector and print them out

Example:

#include <vector>
#include <string>

//Custom data type
class Person {
public:
	Person(string name, int age) {
		mName = name;
		mAge = age;
	}
public:
	string mName;
	int mAge;
};
//Storage object
void test01() {

	vector<Person> v;

	//Create data
	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;

	}
}


//Drop object pointer
void test02() {

	vector<Person*> v;

	//Create data
	Person p1("aaa", 10);
	Person p2("bbb", 20);
	Person p3("ccc", 30);
	Person p4("ddd", 40);
	Person p5("eee", 50);

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

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


int main() {

	test01();
    
	test02();

	system("pause");

	return 0;
}

2.5.3 Vector container nested container

Learning goal: nested containers in containers, we will traverse all data and output

Example:

#include <vector>

//Container nested container
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);
	}

	//Insert the container element into the vector v
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	v.push_back(v4);


	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) {

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

}

int main() {

	test01();

	system("pause");

	return 0;
}

3 STL - Common containers

3.1 string container

3.1.1 basic concept of string

Essence:

  • 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 with char * encapsulated inside. It is a container of char * type to manage this string.

characteristic:

string class encapsulates many member methods

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

string manages the memory allocated by char * without worrying about copy out of bounds and value out of bounds. It is the responsibility of the class

3.1.2 string constructor

Constructor prototype:

  • string(); // Create an empty string, for example: string str;
    string(const char* s); // Initialize with string s
  • string(const string& str); // Initializing another string object with one string object
  • string(int n, char c); // Initialize with n characters C

Example:

#include <string>
//string construction
void test01()
{
	string s1; //Create an empty string and call the parameterless constructor
	cout << "str1 = " << s1 << endl;

	const char* str = "hello world";
	string s2(str); //Put c_string converted to string

	cout << "str2 = " << s2 << endl;

	string s3(s2); //Call copy constructor
	cout << "str3 = " << s3 << endl;

	string s4(10, 'a');
	cout << "str3 = " << s3 << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: there is no comparability in the various construction methods of string, so it can be used flexibly

3.1.3 string assignment

Function Description:

  • Assign a value to a string

Prototype of assigned function:

  • 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); // The character is assigned 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 string s to the current string
  • string& assign(const string &s); // Assign string s to the current string
  • string& assign(int n, char c); // Assign n characters C to the current string

Example:

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

Summary:

There are many ways to assign values to string s, and operator = is more practical

3.1.4 string splicing

Function Description:

  • Implements splicing strings at the end of a string

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); // Connects the string s to the end of the current string
  • string& append(const char *s, int n); // Connect the first n characters of string s to the end of the current string
  • string& append(const string &s); // Same as operator + = (const string & STR)
  • string& append(const string &s, int pos, int n);// N characters from POS in string s are connected to the end of the string

Example:

//String splicing
void test01()
{
	string str1 = "I";

	str1 += "Love playing games";

	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); // Starting from the subscript 4 position, intercept 3 characters and splice them to the end of the string
	cout << "str3 = " << str3 << endl;
}
int main() {

	test01();

	system("pause");

	return 0;
}

Summary: there are many overloaded versions of string splicing. Just remember several at the beginning of learning

3.1.5 string find and replace

Function Description:

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

Function prototype:

  • int find(const string& str, int pos = 0) const; // Find the location where STR appears for the first time, starting from POS
  • int find(const char* s, int pos = 0) const; // Find the location where s first appears, starting from POS
  • int find(const char* s, int pos, int n) const; // Find the first position of the first n characters of s from the POS position
  • int find(const char c, int pos = 0) const; // Find where the character c first appears
  • 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 location of the last occurrence of S, starting from POS
  • int rfind(const char* s, int pos, int n) const; // Find the last position of the first n characters of s from POS
  • int rfind(const char c, int pos = 0) const; // Find the last occurrence of character c
  • string& replace(int pos, int n, const string& str); // Replace n characters starting from POS with string str
  • string& replace(int pos, int n,const char* s); // Replace the n characters starting from POS with the string s

Example:

//Find and replace
void test01()
{
	//lookup
	string str1 = "abcdefgde";

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

	if (pos == -1)
	{
		cout << "not found" << endl;
	}
	else
	{
		cout << "pos = " << pos << endl;
	}
	

	pos = str1.rfind("de");

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

}

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

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

int main() {

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

	system("pause");

	return 0;
}

Summary:

  • find is from left to back, and rfind is from right to left
  • find returns the position of the first character after finding the string. If not, it returns - 1
  • When replacing, you need to specify where to start, how many characters to replace and what kind of string to replace

3.1.6 string comparison

Function Description:

  • Comparison between strings

Comparison method:

  • String comparison is based on the ASCII code of characters

=Return 0

>Return 1

< return - 1

Function prototype:

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

Example:

//string comparison
void test01()
{

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

	int ret = s1.compare(s2);

	if (ret == 0) {
		cout << "s1 be equal to s2" << endl;
	}
	else if (ret > 0)
	{
		cout << "s1 greater than s2" << endl;
	}
	else
	{
		cout << "s1 less than s2" << endl;
	}

}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: string comparison is mainly used to compare whether two strings are equal. It is not of great significance to judge who is big and who is small

3.1.7 string character access

There are two ways to access a single character in a string

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

Example:

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

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

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


	//Character modification
	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 from a 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 in the specified position C
  • string& erase(int Pos, int n = npos); // Delete n characters starting from Pos

Example:

//String insertion and deletion
void test01()
{
	string str = "hello";
	str.insert(1, "111");
	cout << str << endl;

	str.erase(1, 3);  //3 characters from position 1
	cout << str << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * the initial subscripts of insertion and deletion start from 0

3.1.9 string substring

Function Description:

  • Get the desired substring from the string

Function prototype:

  • string substr(int pos = 0, int n = npos) const; // Returns a string of n characters starting with POS

Example:

//Substring
void test01()
{

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

	string email = "hello@sina.com";
	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 substring function can obtain effective information in actual development

3.2 vector container

3.2.1 basic concept of vector

Function:

  • vector data structure is very similar to array, also known as single ended array

The difference between vector and ordinary array:

  • The difference is that the array is a static space, while the vector can be extended dynamically

Dynamic expansion:

  • Instead of adding a new space after the original space, 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 constructor

Function Description:

  • Create vector container

Function prototype:

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

Example:

#include <vector>

void printVector(vector<int>& v) {

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

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

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

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

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * many construction methods of vector are not comparable and can be used flexibly

3.2.3 vector assignment

Function Description:

  • Assign a value to the vector container

Function prototype:

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

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

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

Example:

#include <vector>

void printVector(vector<int>& v) {

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

//Assignment operation
void test01()
{
	vector<int> v1; //Nonparametric structure
	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;
}

Conclusion: the assignment method of vector is relatively simple. You can use operator =, or assign

3.2.4 vector capacity and size

Function Description:

  • Operation on the capacity and size of the vector container

Function prototype:

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

  • capacity(); // Capacity of container

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

  • resize(int num); // Reassign the length of the container to num. if the container becomes longer, the new location will be filled with the default value.

    / / if the container becomes shorter, the element whose end exceeds the length of the container will be deleted.

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

    / / if the container becomes shorter, the element whose end exceeds the length of the container will be deleted

Example:

#include <vector>

void printVector(vector<int>& v) {

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

void test01()
{
	vector<int> v1;
	for (int i = 0; i < 10; i++)
	{
		v1.push_back(i);
	}
	printVector(v1);
	if (v1.empty())
	{
		cout << "v1 Empty" << endl;
	}
	else
	{
		cout << "v1 Not empty" << endl;
		cout << "v1 Capacity of = " << v1.capacity() << endl;
		cout << "v1 Size of = " << v1.size() << endl;
	}

	//resize re specifies the size. If the specified size is larger, the new location will be filled with 0 by default. You can use the overloaded version to replace the default filling
	v1.resize(15,10);
	printVector(v1);

	//resize re specifies the size. If the specified size is smaller, the excess elements will be deleted
	v1.resize(5);
	printVector(v1);
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Judge whether it is empty empty
  • Return the number of elements - size
  • Return container capacity - capacity
  • Resize - resize

3.2.5 vector insertion and deletion

Function Description:

  • Insert and delete the vector container

Function prototype:

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

Example:

#include <vector>

void printVector(vector<int>& v) {

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

//Insert and delete
void test01()
{
	vector<int> v1;
	//Tail insertion
	v1.push_back(10);
	v1.push_back(20);
	v1.push_back(30);
	v1.push_back(40);
	v1.push_back(50);
	printVector(v1);
	//Tail deletion
	v1.pop_back();
	printVector(v1);
	//insert
	v1.insert(v1.begin(), 100);
	printVector(v1);

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

	//delete
	v1.erase(v1.begin());
	printVector(v1);

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Tail push_back
  • Tail deletion pop_back
  • Insert insert (position iterator)
  • Delete - erase (position iterator)
  • Empty - clear

3.2.6 vector data access

Function Description:

  • Access to data in vector

Function prototype:

  • at(int idx); // Returns the data indicated by the index idx
  • operator[]; // Returns the data indicated by the index idx
  • front(); // Returns the first data element in the container
  • 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 The first element of is: " << v1.front() << endl;
	cout << "v1 The last element of the is: " << v1.back() << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

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

3.2.7 vector interchange container

Function Description:

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

	//Interchangeable container
	cout << "After exchange" << endl;
	v1.swap(v2);
	printVector(v1);
	printVector(v2);
}

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

	cout << "v The capacity of the is:" << v.capacity() << endl;
	cout << "v The size of the is:" << v.size() << endl;

	v.resize(3);

	cout << "v The capacity of the is:" << v.capacity() << endl;
	cout << "v The size of the is:" << v.size() << endl;

	//Shrink memory
	vector<int>(v).swap(v); //Anonymous object

	cout << "v The capacity of the is:" << v.capacity() << endl;
	cout << "v The size of the is:" << v.size() << endl;
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

Conclusion: swap can exchange two containers and achieve the practical effect of shrinking memory

3.2.8 reserved space for vector

Function Description:

  • Reduce the expansion times of vector when dynamically expanding capacity

Function prototype:

  • reserve(int len);// The container reserves len element lengths. The reserved positions are not initialized and the elements are inaccessible.

Example:

#include <vector>

void test01()
{
	vector<int> v;

	//Reserved space
	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;
}

Conclusion: if the amount of data is large, reserve space can be used to reserve space at the beginning

3.3 deque container

3.3.1 basic concept of deque container

Function:

  • Double ended array, which can insert and delete the head end

The difference between deque and vector:

  • vector is inefficient for inserting and deleting headers. The larger the amount of data, the lower the efficiency
  • deque relatively speaking, the insertion and deletion speed of the head is faster than that of the vector
  • vector accesses elements faster than deque, which is related to their internal implementation

Internal working principle of deque:

deque has a central controller inside, 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 deque container also supports random access

3.3.2 deque constructor

Function Description:

  • deque vessel construction

Function prototype:

  • deque<T> deqT; // Default construction form
  • deque(beg, end); // Copy the element in the [End] constructor 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 structure
void test01() {

	deque<int> d1; //non-parameter constructor 
	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 structure of deque container and vector container are almost the same, which can be used flexibly

3.3.3 deque assignment

Function Description:

  • Assign a value to the deque container

Function prototype:

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

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

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

Example:

#include <deque>

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

	}
	cout << endl;
}
//Assignment operation
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;
}

Conclusion: the deque assignment operation is also the same as that of vector, which needs to be mastered

3.3.4 deque size operation

Function Description:

  • Operate on the size of the deque container

Function prototype:

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

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

  • deque.resize(num); // Reassign the length of the container to num. if the container becomes longer, the new location will be filled with the default value.

    / / if the container becomes shorter, the element whose end exceeds the length of the container will be deleted.

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

    / / if the container becomes shorter, the element whose end exceeds the length of the container will be deleted.

Example:

#include <deque>

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

	}
	cout << endl;
}

//Size operation
void test01()
{
	deque<int> d1;
	for (int i = 0; i < 10; i++)
	{
		d1.push_back(i);
	}
	printDeque(d1);

	//Determine whether the container is empty
	if (d1.empty()) {
		cout << "d1 Empty!" << endl;
	}
	else {
		cout << "d1 Not empty!" << endl;
		//Statistical size
		cout << "d1 The size of the is:" << d1.size() << endl;
	}

	//Reassign size
	d1.resize(15, 1);
	printDeque(d1);

	d1.resize(5);
	printDeque(d1);
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • deque has no concept of capacity
  • Judge whether it is empty empty
  • Return the number of elements - size
  • Reassign number - resize

3.3.5 deque insertion and deletion

Function Description:

  • Inserting and deleting data into the deque container

Function prototype:

Insert at both ends:

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

Specify location operation:

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

  • insert(pos,n,elem); // Insert n elem data in POS position, and there is no return value.

  • insert(pos,beg,end); // Insert the data of the [beg, end) interval in the POS position, and there is no return value.

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

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

  • erase(pos); // Delete the data in POS position and return to 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;
}
//Two end operation
void test01()
{
	deque<int> d;
	//Tail insertion
	d.push_back(10);
	d.push_back(20);
	//Head insert
	d.push_front(100);
	d.push_front(200);

	printDeque(d);

	//Tail deletion
	d.pop_back();
	//Header deletion
	d.pop_front();
	printDeque(d);
}

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

}

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

Summary:

  • Insert and delete the position provided is an iterator!
  • Tail push_back
  • Tail deletion pop_back
  • Head push_front
  • Header deletion - pop_front

3.3.6 deque data access

Function Description:

  • Access to data in deque

Function prototype:

  • at(int idx); // Returns the data indicated by the index idx
  • operator[]; // Returns the data indicated 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;
}

//data access 
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;
}

Summary:

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

3.3.7 deque sorting

Function Description:

  • Using algorithm to sort deque containers

Algorithm:

  • sort(iterator beg, iterator end) / / sort the elements in the beg and end intervals

Example:

#include <deque>
#include <algorithm>

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

	}
	cout << endl;
}

void test01()
{

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

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

}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: the sort algorithm is very practical. When used, it can include the header file algorithm

3.4 cases - scoring by judges

3.4.1 case description

There are five contestants: contestant ABCDE, and 10 judges will score each contestant respectively, removing the highest score and the lowest score among the judges, and taking 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 scores into the deque container
  3. sort algorithm sorts the scores in deque container to remove the highest and lowest scores
  4. The deque container is traversed and the total score is accumulated
  5. Get average score

Example code:

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

	string m_Name; //full name
	int m_Score;  //average
};

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

		int score = 0;

		Person p(name, score);

		//Put the created person object into the container
		v.push_back(p);
	}
}

//Score
void setScore(vector<Person>&v)
{
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		//Put the judges' scores into the deque container
		deque<int>d;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 41 + 60;  // 60 ~ 100
			d.push_back(score);
		}

		//Cout < < player: "< it - > m_ Name < < score: "< endl;
		//for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
		//{
		//	cout << *dit << " ";
		//}
		//cout << endl;

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

		//Remove the highest and lowest scores
		d.pop_back();
		d.pop_front();

		//Average score
		int sum = 0;
		for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			sum += *dit; //Accumulate the scores of each judge
		}

		int avg = sum / d.size();

		//Assign the average score to the player
		it->m_Score = avg;
	}

}

void showScore(vector<Person>&v)
{
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "full name: " << it->m_Name << " average: " << it->m_Score << endl;
	}
}

int main() {

	//Random number seed
	srand((unsigned int)time(NULL));

	//1. Create 5 players
	vector<Person>v;  //Container for storing players
	createPerson(v);

	//test
	//for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
	//{
	//	Cout < < "Name:" < < (* it) m_ Name < < "score:" < < (* it) m_ Score << endl;
	//}

	//2. Score five players
	setScore(v);

	//3. Show last score
	showScore(v);

	system("pause");

	return 0;
}

Conclusion: selecting different container operation 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 with only one exit

Only the top elements in the stack can be used by the outside world, so the stack is not allowed to traverse

Data entering the stack is called - push

The pop-up data in the stack is called out of stack pop

3.5.2 common interfaces of stack

Function Description: common external interface of stack container

Constructor:

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

Assignment operation:

  • stack& operator=(const stack &stk); // Overloaded equal sign 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 stack top element

Size operation:

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

Example:

#include <stack>

//Common interface of stack container
void test01()
{
	//Create stack containers. Stack containers must comply with the requirements of first in first out
	stack<int> s;

	//Adding elements to the stack is called pushing on the stack
	s.push(10);
	s.push(20);
	s.push(30);

	while (!s.empty()) {
		//Output stack top element
		cout << "Stack top elements are: " << s.top() << endl;
		//Pop up stack top element
		s.pop();
	}
	cout << "The stack size is:" << s.size() << endl;

}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Stack push
  • Out of stack - pop
  • Return to top of 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 (FIFO) data structure with two exits

Queue containers allow you to add elements from one end and remove elements from the other

Only the head and tail of the queue can be used by the outside world, so the queue is not allowed to traverse

Incoming data in the queue is called - incoming push

Out of queue data is called out of queue pop

3.6.2 common interfaces of queue

Function Description: common external interface of stack container

Constructor:

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

Assignment operation:

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

Data access:

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

Size operation:

  • empty(); // Determine whether the stack is empty
  • size(); // Returns 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() {

	//Create queue
	queue<Person> q;

	//Prepare data
	Person p1("Tang Monk", 30);
	Person p2("Sun WuKong", 1000);
	Person p3("Zhu Bajie", 900);
	Person p4("Monk Sha", 800);

	//Adding elements to a queue
	q.push(p1);
	q.push(p2);
	q.push(p3);
	q.push(p4);

	//Queues do not provide iterators, nor do they support random access	
	while (!q.empty()) {
		//Output header element
		cout << "Team head element-- full name: " << q.front().m_Name 
              << " Age: "<< q.front().m_Age << endl;
        
		cout << "Tail element-- full name: " << q.back().m_Name  
              << " Age: " << q.back().m_Age << endl;
        
		cout << endl;
		//Pop up queue header element
		q.pop();
	}

	cout << "The queue size is:" << q.size() << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Join the team - push
  • Out of line - pop
  • Return queue header element - front
  • Return to end of queue element - back
  • Judge whether the queue is empty empty
  • Return queue size - size

3.7 container

3.7.1 basic concept of list

**Function: * * chain store data

A linked list is a discontinuous storage structure on a physical storage unit. The logical order of data elements is realized through pointer links in the linked list

Composition of linked list: the linked list is composed of a series of nodes

Composition of nodes: one is the data field for storing data elements, and the other is the pointer field for storing the address of the next node

STL is a two-way linked list

Because the storage mode of the linked list is not a continuous memory space, the iterator in the linked list only supports forward and backward, which belongs to a two-way iterator

Advantages of list:

  • Dynamic storage allocation will not cause memory waste and overflow
  • It is very convenient to insert and delete the linked list. You can modify the pointer without moving a large number of elements

Disadvantages of list:

  • The linked list is flexible, but the additional cost of space (pointer field) and time (traversal) is large

List has an important property. Neither insert operation nor delete operation will cause the invalidation of the original list iterator, which is not tenable in vector.

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

3.7.2 list constructor

Function Description:

  • Create a list container

Function prototype:

  • list<T> lst; // List is implemented by template class, and the default construction form of object is:
  • list(beg,end); // Copy the element in the [End] constructor 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 structure of list is the same as that of several other STL common containers, which can be mastered skillfully

3.7.3 list assignment and exchange

Function Description:

  • Assign values to the list container and exchange list containers

Function prototype:

  • assign(beg, end); // Assign the data copy in the [beg, end) interval to itself.
  • assign(n, elem); // Assign n elem copies to itself.
  • list& operator=(const list &lst); // Overloaded equal sign 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;
}

//Assignment and exchange
void test01()
{
	list<int>L1;
	L1.push_back(10);
	L1.push_back(20);
	L1.push_back(30);
	L1.push_back(40);
	printList(L1);

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

}

//exchange
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 << "Before exchange: " << endl;
	printList(L1);
	printList(L2);

	cout << endl;

	L1.swap(L2);

	cout << "After exchange: " << endl;
	printList(L1);
	printList(L2);

}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

Conclusion: list assignment and exchange can be used flexibly

3.7.4 list size operation

Function Description:

  • Operate on the size of the list container

Function prototype:

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

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

  • resize(num); // Reassign the length of the container to num. if the container becomes longer, the new location will be filled with the default value.

    / / if the container becomes shorter, the element whose end exceeds the length of the container will be deleted.

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

      	 	 						    //If the container becomes shorter, the element whose end exceeds the length of the container is 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;
}

//Size operation
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 Empty" << endl;
	}
	else
	{
		cout << "L1 Not empty" << endl;
		cout << "L1 The size of the is: " << L1.size() << endl;
	}

	//Reassign size
	L1.resize(10);
	printList(L1);

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Judge whether it is empty empty
  • Return the number of elements - size
  • Reassign number - resize

3.7.5 list insertion and deletion

Function Description:

  • Insert and delete data from 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 in the POS position and return the location of the new data.
  • insert(pos,n,elem);// Insert n elem data in POS position, and there is no return value.
  • insert(pos,beg,end);// Insert the data of the [beg, end) interval in the POS position, and there is no return value.
  • clear();// Remove all data from the container
  • erase(beg,end);// Delete the data in the [beg, end) interval and return the position of the next data.
  • erase(pos);// Delete the data in POS position and return to the position of the next data.
  • remove(elem);// Delete all elements in the container that match the element value.

Example:

#include <list>

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

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

//Insert and delete
void test01()
{
	list<int> L;
	//Tail insertion
	L.push_back(10);
	L.push_back(20);
	L.push_back(30);
	//Head insert
	L.push_front(100);
	L.push_front(200);
	L.push_front(300);

	printList(L);

	//Tail deletion
	L.pop_back();
	printList(L);

	//Header deletion
	L.pop_front();
	printList(L);

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

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

	//remove
	L.push_back(10000);
	L.push_back(10000);
	L.push_back(10000);
	printList(L);
	L.remove(10000);
	printList(L);
    
    //empty
	L.clear();
	printList(L);
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Tail push_back
  • Tail deletion pop_back
  • Head push_front
  • Header deletion - 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(); // Returns the first element.
  • back(); // Returns the last element.

Example:

#include <list>

//data access 
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;// Error: at access to data is not supported
	//cout << L1[0] << endl; // Error: accessing data in [] mode is not supported
	cout << "The first element is: " << L1.front() << endl;
	cout << "The last element is: " << L1.back() << endl;

	//The iterator of the list container is a bidirectional iterator and does not support random access
	list<int>::iterator it = L1.begin();
	//it = it + 1;// Error, cannot skip access, even + 1
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

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

Reverse sort and list 3.7

Function Description:

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

Function prototype:

  • reverse(); // Reverse linked list
  • sort(); // Linked list sorting

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

//Reverse and sort
void test01()
{
	list<int> L;
	L.push_back(90);
	L.push_back(30);
	L.push_back(20);
	L.push_back(70);
	printList(L);

	//Invert the elements of the container
	L.reverse();
	printList(L);

	//sort
	L.sort(); //The default collation is from small to large
	printList(L);

	L.sort(myCompare); //Specify rules, from large to small
	printList(L);
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Reverse reverse
  • Sort - sort (member function)

3.7.8 sorting cases

Case description: sort the user-defined data type of Person. The attributes in Person include name, age and height

Sorting rule: ascending by age, descending 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;  //full name
	int m_Age;      //Age
	int m_Height;   //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("Liu Bei", 35 , 175);
	Person p2("Cao Cao", 45 , 180);
	Person p3("Sun Quan", 40 , 170);
	Person p4("Zhao Yun", 25 , 190);
	Person p5("Fei Zhang", 35 , 160);
	Person p6("Guan Yu", 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 << "full name: " << it->m_Name << " Age: " << it->m_Age 
              << " Height: " << it->m_Height << endl;
	}

	cout << "---------------------------------" << endl;
	L.sort(ComparePerson); //sort

	for (list<Person>::iterator it = L.begin(); it != L.end(); it++) {
		cout << "full name: " << it->m_Name << " Age: " << it->m_Age 
              << " Height: " << it->m_Height << endl;
	}
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

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

3.8.1 basic concept of set

Introduction:

  • All elements are automatically sorted on insertion

Essence:

  • set/multiset is an associative container, and its underlying structure is implemented by binary tree.

Difference between set and multiset:

  • set does not allow duplicate elements in the container
  • multiset allows duplicate elements in a container

3.8.2 set construction and assignment

Function Description: create set container and assign value

Construction:

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

Assignment:

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

Example:

#include <set>

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

//Construction and assignment
void test01()
{
	set<int> s1;

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

	//copy construction 
	set<int>s2(s1);
	printSet(s2);

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • insert is used 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:

  • Count the size of set container and exchange set container

Function prototype:

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

Example:

#include <set>

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

//size
void test01()
{

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

	if (s1.empty())
	{
		cout << "s1 Empty" << endl;
	}
	else
	{
		cout << "s1 Not empty" << endl;
		cout << "s1 The size of the is: " << s1.size() << endl;
	}

}

//exchange
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 << "Before exchange" << endl;
	printSet(s1);
	printSet(s2);
	cout << endl;

	cout << "After exchange" << endl;
	s1.swap(s2);
	printSet(s1);
	printSet(s2);
}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary:

  • Statistical size - size
  • Judge whether it is empty empty
  • swap container - swap

3.8.4 set insertion and deletion

Function Description:

  • The set container inserts and deletes data

Function prototype:

  • insert(elem); // Insert an element into the container.
  • clear(); // Clear all elements
  • erase(pos); // Delete the element referred to by the POS iterator and return the iterator of the next element.
  • erase(beg,end); // Delete all elements of the interval [beg, end], and return the iterator of the next element.
  • erase(elem); // Delete the element with element 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;
}

//Insert and delete
void test01()
{
	set<int> s1;
	//insert
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	printSet(s1);

	//delete
	s1.erase(s1.begin());
	printSet(s1);

	s1.erase(30);
	printSet(s1);

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Insert - insert
  • Delete erase
  • Empty - clear

3.8.5 set search and statistics

Function Description:

  • Search data and statistics of set container

Function prototype:

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

Example:

#include <set>

//Search and statistics
void test01()
{
	set<int> s1;
	//insert
	s1.insert(10);
	s1.insert(30);
	s1.insert(20);
	s1.insert(40);
	
	//lookup
	set<int>::iterator pos = s1.find(30);

	if (pos != s1.end())
	{
		cout << "Found element: " << *pos << endl;
	}
	else
	{
		cout << "Element not found" << endl;
	}

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Find - find (the iterator is returned)
  • Statistics - count (for set, the result is 0 or 1)

3.8.6 difference between set and multiset

Learning objectives:

  • Master the difference between set and multiset

difference:

  • set cannot insert duplicate data, while multiset can
  • set will return the insertion result when inserting data, indicating whether the insertion is successful
  • multiset does not detect data, so duplicate data can be inserted

Example:

#include <set>

//Difference between set and multiset
void test01()
{
	set<int> s;
	pair<set<int>::iterator, bool>  ret = s.insert(10);
	if (ret.second) {
		cout << "First insertion successful!" << endl;
	}
	else {
		cout << "First insertion failed!" << endl;
	}

	ret = s.insert(10);
	if (ret.second) {
		cout << "The second insertion was successful!" << endl;
	}
	else {
		cout << "The second insertion failed!" << 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;
}

Summary:

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

3.8.7 pair group creation

Function Description:

  • For paired data, two data can be returned by using the pair group

There are two creation methods:

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

Example:

#include <string>

//Create a group
void test01()
{
	pair<string, int> p(string("Tom"), 20);
	cout << "full name: " <<  p.first << " Age: " << p.second << endl;

	pair<string, int> p2 = make_pair("Jerry", 10);
	cout << "full name: " << p2.first << " Age: " << p2.second << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

You can create pair groups in both ways. Just remember one

3.8.8 set container sorting

Learning objectives:

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

Main technical points:

  • Using the imitation function, the sorting rules can be changed

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

	//Default from small to large
	for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//Specify collation
	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: the sorting rules of the set container can be specified by using the imitation function

Example 2: storing user-defined 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)
	{
		//Sort by age, descending
		return p1.m_Age > p2.m_Age;
	}
};

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

	Person p1("Liu Bei", 23);
	Person p2("Guan Yu", 27);
	Person p3("Fei Zhang", 25);
	Person p4("Zhao Yun", 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 << "full name: " << it->m_Name << " Age: " << it->m_Age << endl;
	}
}
int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

For user-defined data types, set must specify sorting rules before inserting data

3.9 map/ multimap container

3.9.1 basic concept of map

Introduction:

  • All elements in the map are pair
  • The first element in pair is key (key value), which serves as an index, and the second element is value (real value)
  • All elements are automatically sorted according to the key value of the element

Essence:

  • map/multimap is an associative container, and its underlying structure is implemented by binary tree.

advantage:

  • You can quickly find the value value according to the key value

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 the map container

Function prototype:

Construction:

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

Assignment:

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

Example:

#include <map>

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

void test01()
{
	map<int,int>m; //Default construction
	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); //copy construction 
	printMap(m2);

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

int main() {

	test01();

	system("pause");

	return 0;
}

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

3.9.3 map size and swap

Function Description:

  • Count the size of map container and exchange map container

Function prototype:

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

Example:

#include <map>

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

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

	if (m.empty())
	{
		cout << "m Empty" << endl;
	}
	else
	{
		cout << "m Not empty" << endl;
		cout << "m The size of the is: " << m.size() << endl;
	}
}


//exchange
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 << "Before exchange" << endl;
	printMap(m);
	printMap(m2);

	cout << "After exchange" << endl;
	m.swap(m2);
	printMap(m);
	printMap(m2);
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

Summary:

  • Statistical size - size
  • Judge whether it is empty empty
  • swap container - swap

3.9.4 map insertion and deletion

Function Description:

  • The map container inserts and deletes data

Function prototype:

  • insert(elem); // Insert an element into the container.
  • clear(); // Clear all elements
  • erase(pos); // Delete the element referred to by the POS iterator and return the iterator of the next element.
  • erase(beg,end); // Delete all elements of the interval [beg, end], and return the iterator of the next element.
  • erase(key); // Delete the element with 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()
{
	//insert
	map<int, int> m;
	//First insertion method
	m.insert(pair<int, int>(1, 10));
	//Second insertion method
	m.insert(make_pair(2, 20));
	//The third insertion method
	m.insert(map<int, int>::value_type(3, 30));
	//The fourth insertion method
	m[4] = 40; 
	printMap(m);

	//delete
	m.erase(m.begin());
	printMap(m);

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

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

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

  • Search the map container for data and statistics

Function prototype:

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

Example:

#include <map>

//Search and statistics
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));

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

	if (pos != m.end())
	{
		cout << "Element found key = " << (*pos).first << " value = " << (*pos).second << endl;
	}
	else
	{
		cout << "Element not found" << endl;
	}

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

int main() {

	test01();

	system("pause");

	return 0;
}

Summary:

  • Find - find (the iterator is returned)
  • Statistics - count (for map, the result is 0 or 1)

3.9.6 map container sorting

Learning objectives:

  • The default sorting rule of 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 the imitation function, the sorting rules can be changed

Example:

#include <map>

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

void test01() 
{
	//Default sort from small to large
	//Sorting from large to small by using imitation function
	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;
}

Summary:

  • The sorting rules of the map container can be specified by using the affine function
  • For user-defined data types, map must specify sorting rules, the same as set container

3.10 case - employee grouping

3.10.1 case description

  • Today, the company recruited 10 employees (ABCDEFGHIJ). After 10 employees enter the company, they need to assign employees to work in that department
  • Employee information includes: name and salary composition; R & D and art planning departments
  • Randomly assign department and salary 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 into the vector
  2. Traverse the vector container, take out each employee and group them randomly
  3. After grouping, put the employee department number as the key and the specific employee as the value 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>

/*
- Today, the company recruited 10 employees (ABCDEFGHIJ). After 10 employees enter the company, they need to assign employees to work in that department
- Employee information includes: name and salary composition; The departments are divided into: planning, art and R & D
- Randomly assign department and salary to 10 employees
- Insert information through multimap key (department number) value (employee)
- Display employee information by Department
*/

#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 = "staff";
		worker.m_Name += nameSeed[i];

		worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999
		//Put employees into containers
		v.push_back(worker);
	}
}

//Employee grouping
void setGroup(vector<Worker>&v,multimap<int,Worker>&m)
{
	for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++)
	{
		//Generate random department number
		int deptId = rand() % 3; // 0 1 2 

		//Insert employees into groups
		//key department number, value specific employee
		m.insert(make_pair(deptId, *it));
	}
}

void showWorkerByGourp(multimap<int,Worker>&m)
{
	// 0  A  B  C   1  D  E   2  F G ...
	cout << "Planning department:" << endl;

	multimap<int,Worker>::iterator pos = m.find(CEHUA);
	int count = m.count(CEHUA); // Count the specific number of people
	int index = 0;
	for (; pos != m.end() && index < count; pos++ , index++)
	{
		cout << "full name: " << pos->second.m_Name << " Salary: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "Art Department: " << endl;
	pos = m.find(MEISHU);
	count = m.count(MEISHU); // Count the specific number of people
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "full name: " << pos->second.m_Name << " Salary: " << pos->second.m_Salary << endl;
	}

	cout << "----------------------" << endl;
	cout << "R & D department: " << endl;
	pos = m.find(YANFA);
	count = m.count(YANFA); // Count the specific number of people
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "full name: " << pos->second.m_Name << " Salary: " << pos->second.m_Salary << endl;
	}

}

int main() {

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

	//1. Create employee
	vector<Worker>vWorker;
	createWorker(vWorker);

	//2. Employee grouping
	multimap<int, Worker>mWorker;
	setGroup(vWorker, mWorker);


	//3. Show employees in groups
	showWorkerByGourp(mWorker);

	test
	//for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++)
	//{
	//	Cout < < name: "< it - > m_ Name < < salary: "< it - > m_ Salary << endl;
	//}

	system("pause");

	return 0;
}

Summary:

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

4 STL function object

4.1 function object

4.1.1 function object concept

Concept:

  • A class that overloads the function call operator. Its object is often called a function object
  • When a function object uses overloaded (), its behavior is similar to that of a function call, which is also called an imitation function

Essence:

A function object is a class, not a function

4.1.2 function object usage

characteristic:

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

Example:

#include <string>

//1. When a function object is used, it can be called like an ordinary function, with parameters and return values
class MyAdd
{
public :
	int operator()(int v1,int v2)
	{
		return v1 + v2;
	}
};

void test01()
{
	MyAdd myAdd;
	cout << myAdd(10, 10) << endl;
}

//2. Function objects can have their own state
class MyPrint
{
public:
	MyPrint()
	{
		count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl;
		count++; //Count usage times
	}

	int count; //Internal self state
};
void test02()
{
	MyPrint myPrint;
	myPrint("hello world");
	myPrint("hello world");
	myPrint("hello world");
	cout << "myPrint The number of calls is: " << myPrint.count << endl;
}

//3. Function objects can be passed as arguments
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;
}

Summary:

  • The imitation function is very flexible and can be passed as a parameter.

4.2 predicate

4.2.1 predicate concept

Concept:

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

4.2.2 unary predicate

Example:

#include <vector>
#include <algorithm>

//1. Unary predicate
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 << "Can't find!" << endl;
	}
	else {
		cout << "find:" << *it << endl;
	}

}

int main() {

	test01();

	system("pause");

	return 0;
}

Summary: predicates with only one parameter are called unary predicates

4.2.3 binary predicate

Example:

#include <vector>
#include <algorithm>
//two-place predicate
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);

	//Default from small to large
	sort(v.begin(), v.end());
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	cout << "----------------------------" << endl;

	//Use the function object to change the algorithm strategy and sort from large to small
	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: predicates with only two parameters are called binary predicates

4.3 built in function object

4.3.1 meaning of built-in function object

Concept:

  • STL has built-in function objects

Classification:

  • Arithmetic imitation function

  • Relational affine function

  • Logical imitation function

Usage:

  • The usage of the objects generated by these imitation functions is exactly the same as that of general functions
  • To use the built-in function object, you need to import the header file #include < functional >

4.3.2 arithmetic imitation function

Function Description:

  • Realize four operations
  • Among them, negate is a unary operation, and others are binary operations

Imitation function prototype:

  • Template < class T > t plus < T > / / addition functor
  • Template < class T > t minus < T > / / subtraction function
  • Template < class T > t multiples < T > / / multiplication functor
  • Template < class T > t divisions < T > / / division imitation function
  • Template < class T > t module < T > / / take the imitation function
  • Template < class T > t negate < T > / / take the inverse function

Example:

#include <functional>
//negate
void test01()
{
	negate<int> n;
	cout << n(50) << endl;
}

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

int main() {

	test01();
	test02();

	system("pause");

	return 0;
}

Summary: when using built-in function objects, the header file #include < functional > needs to be introduced

4.3.3 relation imitation function

Function Description:

  • Implement relationship comparison

Imitation function prototype:

  • template<class T> bool equal_ To < T > / / equal to
  • template<class T> bool not_ equal_ To < T > / / not equal to
  • Template < class T > bool greater < T > / / greater than
  • template<class T> bool greater_ Equal < T > / / greater than 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;

	//Realize the imitation function by yourself
	//sort(v.begin(), v.end(), MyCompare());
	//STL built-in functor is larger than functor
	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: greater < > greater than is the most commonly used in relational imitation functions

4.3.4 logic imitation function

Function Description:

  • Realize logical operation

Function prototype:

  • template<class T> bool logical_ And < T > / / logic and
  • template<class T> bool logical_ Or < T > / / logical or
  • template<class T> bool logical_ Not < T > / / not logical

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;

	//Logical non carries the v container into v2 and performs logical non operations
	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;
}

Conclusion: there are few practical applications of logic imitation function, so you can understand it

5 STL common algorithms

summary:

  • The algorithm is mainly composed of header file < algorithm > < functional > < numeric >.

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

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

  • < functional > defines some template classes to declare function objects.

5.1 common traversal algorithms

Learning objectives:

  • Master common traversal algorithms

Algorithm Introduction:

  • for_each / / traverse the container
  • transform / / transfer container to another container

5.1.1 for_each

Function Description:

  • Implement traversal container

Function prototype:

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

    //Traversal algorithm traverses container elements

    //beg start iterator

    //End end iterator

    // _ func function or function object

Example:

#include <algorithm>
#include <vector>

//Ordinary function
void print01(int val) 
{
	cout << val << " ";
}
//Function object
class print02 
{
 public:
	void operator()(int val) 
	{
		cout << val << " ";
	}
};

//for_ Basic usage of each algorithm
void test01() {

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

	//inorder traversal 
	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 practical development, which needs to be mastered skillfully

5.1.2 transform

Function Description:

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

//Common traversal algorithms

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; //Target container

	vTarget.resize(v.size()); // The target container needs to open up space in advance

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

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

int main() {

	test01();

	system("pause");

	return 0;
}

Conclusion: the target container to be handled must be opened up in advance, otherwise it cannot be handled normally

5.2 common search algorithms

Learning objectives:

  • Master common search algorithms

Algorithm Introduction:

  • Find / / find elements
  • find_if / / find elements by criteria
  • adjacent_find / / find adjacent duplicate elements
  • binary_search / / binary search
  • 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, and cannot find the return end iterator end()

Function prototype:

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

    //Find the element by value, find the iterator that returns the specified position, and the iterator that returns the end cannot be found

    //beg start iterator

    //End end iterator

    //value lookup element

Example:

#include <algorithm>
#include <vector>
#include <string>
void test01() {

	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i + 1);
	}
	//Find out if there is 5 this element in the container
	vector<int>::iterator it = find(v.begin(), v.end(), 5);
	if (it == v.end()) 
	{
		cout << "Can't find!" << endl;
	}
	else 
	{
		cout << "find:" << *it << endl;
	}
}

class Person {
public:
	Person(string name, int age) 
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	//Heavy load==
	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;

	//Create data
	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 << "Can't find!" << endl;
	}
	else 
	{
		cout << "Find name:" << it->m_Name << " Age: " << it->m_Age << endl;
	}
}

Summary: find can find the specified element in the container, and the return value is the iterator

5.2.2 find_if

Function Description:

  • Find elements by criteria

Function prototype:

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

    //Find the element by value, find the iterator that returns the specified position, and the iterator that returns the end cannot be found

    //beg start iterator

    //End end iterator

    // _ Pred function or predicate (an imitation function that returns bool type)

Example:

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

//Built in data type
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 << "Can't find!" << endl;
	}
	else {
		cout << "A number greater than 5 was found:" << *it << endl;
	}
}

//Custom data type
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;

	//Create data
	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 << "Can't find!" << endl;
	}
	else
	{
		cout << "Find name:" << it->m_Name << " Age: " << it->m_Age << endl;
	}
}

int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: find_if search by condition makes the search more flexible, and the provided imitation function 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 repeating elements and return the iterator of the first position of adjacent elements

    //beg start 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);

	//Find adjacent duplicate elements
	vector<int>::iterator it = adjacent_find(v.begin(), v.end());
	if (it == v.end()) {
		cout << "can't find!" << endl;
	}
	else {
		cout << "The adjacent duplicate element found is:" << *it << endl;
	}
}

Conclusion: if you find adjacent repeating elements in the interview question, remember to use the adjacent in STL_ Find algorithm

5.2.4 binary_search

Function Description:

  • Finds whether the specified element exists

Function prototype:

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

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

    //Note: not available in unordered sequences

    //beg start iterator

    //End end iterator

    //value lookup element

Example:

#include <algorithm>
#include <vector>

void test01()
{
	vector<int>v;

	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//Binary search
	bool ret = binary_search(v.begin(), v.end(),2);
	if (ret)
	{
		cout << "eureka" << endl;
	}
	else
	{
		cout << "not found" << endl;
	}
}

int main() {

	test01();

	system("pause");

	return 0;
}

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

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 start iterator

    //End end iterator

    //Element of value statistics

Example:

#include <algorithm>
#include <vector>

//Built in data type
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 The number of is: " << num << endl;
}

//Custom data type
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("Liu Bei", 35);
	Person p2("Guan Yu", 35);
	Person p3("Fei Zhang", 35);
	Person p4("Zhao Yun", 30);
	Person p5("Cao Cao", 25);

	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	v.push_back(p4);
	v.push_back(p5);
    
    Person p("Zhuge Liang",35);

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

	//test01();

	test02();

	system("pause");

	return 0;
}

Summary: when counting user-defined data types, it is necessary to overload the operator==

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 occurrence times of elements by conditions

    //beg start iterator

    //End end iterator

    // _ Pred predicate

Example:

#include <algorithm>
#include <vector>

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

//Built in data type
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 << "The number greater than 4 is: " << num << endl;
}

//Custom data type
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("Liu Bei", 35);
	Person p2("Guan Yu", 35);
	Person p3("Fei Zhang", 35);
	Person p4("Zhao Yun", 30);
	Person p5("Cao Cao", 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 << "Number of children under 35:" << num << endl;
}


int main() {

	//test01();

	test02();

	system("pause");

	return 0;
}

**Summary: * * count by value, count by condition_ if

5.3 common sorting algorithms

Learning objectives:

  • Master common sorting algorithms

Algorithm Introduction:

  • Sort / / sort the elements in the container
  • random_shuffle / / shuffle the elements within the specified range to adjust the order randomly
  • Merge / / merge container elements and store them in another container
  • / / 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, find the iterator that returns the specified position, and the iterator that returns the end cannot be found

    //beg start 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 sorts from small to large by default
	sort(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint);
	cout << endl;

	//Sort from large to small
	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 adjust the order randomly

Function prototype:

  • random_shuffle(iterator beg, iterator end);

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

    //beg start 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;

	//Disorder order
	random_shuffle(v.begin(), v.end());
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * random_shuffle shuffle 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);

    //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;
	//The target container needs to open up space in advance
	vtarget.resize(v1.size() + v2.size());
	//Merging requires two ordered sequences
	merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin());
	for_each(vtarget.begin(), vtarget.end(), myPrint());
	cout << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * merge the ordered sequence of two containers that must be merged

5.3.4 reverse

Function Description:

  • Invert the elements in the container

Function prototype:

  • reverse(iterator beg, iterator end);

    //Inverts the elements of the specified range

    //beg start 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 << "Before reversing: " << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;

	cout << "After reversal: " << endl;

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

int main() {

	test01();

	system("pause");

	return 0;
}

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

5.4 common copy and replacement algorithms

Learning objectives:

  • Master common copy and replacement algorithms

Algorithm Introduction:

  • Copy / / copy the elements of the specified range in the container to another container
  • replace / / modify the old element of the specified range in the container to a new element
  • replace_if / / replace the qualified element in the specified range in the container with a new element
  • Swap / / swap elements of two containers

5.4.1 copy

Function Description:

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

Function prototype:

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

    //Find the element by value, find the iterator that returns the specified position, and the iterator that returns the end cannot be found

    //beg start iterator

    //End end iterator

    //dest target start 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 using the copy algorithm to copy, the target container should remember to open up space in advance

5.4.2 replace

Function Description:

  • Modify the old element of the specified range in the container to a new element

Function prototype:

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

    //Replace the old element in the interval with a new element

    //beg start 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 << "Before replacement:" << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;

	//Replace 20 in container with 2000
	cout << "After replacement:" << 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 qualified elements in the interval

5.4.3 replace_if

Function Description:

  • Replace the qualified elements in the interval with the specified elements

Function prototype:

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

    //Replace the element according to the condition, and replace the qualified element with the specified element

    //beg start iterator

    //End end iterator

    // _ pred predicate

    //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 << "Before replacement:" << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;

	//Replace 30 or more in the container with 3000
	cout << "After replacement:" << 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 search by conditions, you can use the imitation function to flexibly filter the conditions that are met

5.4.4 swap

Function Description:

  • Swap elements of two containers

Function prototype:

  • swap(container c1, container c2);

    //Swap elements of 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 << "Before exchange: " << endl;
	for_each(v1.begin(), v1.end(), myPrint());
	cout << endl;
	for_each(v2.begin(), v2.end(), myPrint());
	cout << endl;

	cout << "After exchange: " << 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 swap containers, pay attention to the same type of containers to be exchanged

5.5 common arithmetic generation algorithms

Learning objectives:

  • Master common arithmetic generation algorithms

be careful:

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

Algorithm Introduction:

  • Calculate / / calculate the cumulative sum of container elements

  • fill / / add element to container

5.5.1 accumulate

Function Description:

  • Calculate the cumulative sum of interval content container elements

Function prototype:

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

    //Calculate the cumulative sum of container elements

    //beg start iterator

    //End end iterator

    //Value starting value

Example:

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

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

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

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * when calculating, the header file should be numeric. This algorithm is very practical

5.5.2 fill

Function Description:

  • Fills the container with the specified element

Function prototype:

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

    //Fill the container with elements

    //beg start 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
	fill(v.begin(), v.end(), 100);

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

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * fill can be used to fill the elements in the container interval with the specified value

5.6 common set algorithms

Learning objectives:

  • Master common set algorithms

Algorithm Introduction:

  • set_intersection / / find the intersection of two containers

  • set_union / / find the union of two containers

  • set_difference / / find the difference set between two containers

5.6.1 set_intersection

Function Description:

  • Find the intersection of two containers

Function prototype:

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

    //Find the intersection of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the smaller of the two values to make room for the target container
	vTarget.resize(min(v1.size(), v2.size()));

	//Returns the iterator address of the last element of the destination container
	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;
}

Summary:

  • Find the ordered sequence of two sets of intersection
  • The target container needs to take a small value from the two containers to open up space
  • set_ The return value of intersection is the position of the last element in the intersection

5.6.2 set_union

Function Description:

  • Find the union of two sets

Function prototype:

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

    //Find the union of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the sum of the two containers to make room for the target container
	vTarget.resize(v1.size() + v2.size());

	//Returns the iterator address of the last element of the destination container
	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;
}

Summary:

  • Union of two ordered sets
  • The target container needs to add two containers to open up space
  • set_ The union return value is the position of the last element in the union set

5.6.3 set_difference

Function Description:

  • Find the difference set of two sets

Function prototype:

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

    //Find the difference set of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the larger of the two values to make room for the target container
	vTarget.resize( max(v1.size() , v2.size()));

	//Returns the iterator address of the last element of the destination container
	cout << "v1 And v2 The difference set of is: " << 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 And v1 The difference set of is: " << 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;
}

Summary:

  • The two sets of difference sets must be ordered sequences

  • The target container needs to take a larger value from the two containers to open up space
    10; i++) {
    v1.push_back(i + 1);
    }
    vector 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:**utilize copy When the algorithm copies, the target container remembers to open up space in advance















#### 5.4.2 replace

**Function Description:**

* Modify the old element of the specified range in the container to a new element



**Function prototype:**

- `replace(iterator beg, iterator end, oldvalue, newvalue);  `

  // Replace the old element in the interval with a new element

  // beg start iterator

  // End end iterator

  // oldvalue old element

  // newvalue new element



**Example:**

```c++
#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 << "Before replacement:" << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;

	//Replace 20 in container with 2000
	cout << "After replacement:" << 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 qualified elements in the interval

5.4.3 replace_if

Function Description:

  • Replace the qualified elements in the interval with the specified elements

Function prototype:

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

    //Replace the element according to the condition, and replace the qualified element with the specified element

    //beg start iterator

    //End end iterator

    // _ pred predicate

    //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 << "Before replacement:" << endl;
	for_each(v.begin(), v.end(), myPrint());
	cout << endl;

	//Replace 30 or more in the container with 3000
	cout << "After replacement:" << 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 search by conditions, you can use the imitation function to flexibly filter the conditions that are met

5.4.4 swap

Function Description:

  • Swap elements of two containers

Function prototype:

  • swap(container c1, container c2);

    //Swap elements of 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 << "Before exchange: " << endl;
	for_each(v1.begin(), v1.end(), myPrint());
	cout << endl;
	for_each(v2.begin(), v2.end(), myPrint());
	cout << endl;

	cout << "After exchange: " << 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 swap containers, pay attention to the same type of containers to be exchanged

5.5 common arithmetic generation algorithms

Learning objectives:

  • Master common arithmetic generation algorithms

be careful:

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

Algorithm Introduction:

  • Calculate / / calculate the cumulative sum of container elements

  • fill / / add element to container

5.5.1 accumulate

Function Description:

  • Calculate the cumulative sum of interval content container elements

Function prototype:

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

    //Calculate the cumulative sum of container elements

    //beg start iterator

    //End end iterator

    //Value starting value

Example:

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

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

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

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * when calculating, the header file should be numeric. This algorithm is very practical

5.5.2 fill

Function Description:

  • Fills the container with the specified element

Function prototype:

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

    //Fill the container with elements

    //beg start 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
	fill(v.begin(), v.end(), 100);

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

int main() {

	test01();

	system("pause");

	return 0;
}

**Summary: * * fill can be used to fill the elements in the container interval with the specified value

5.6 common set algorithms

Learning objectives:

  • Master common set algorithms

Algorithm Introduction:

  • set_intersection / / find the intersection of two containers

  • set_union / / find the union of two containers

  • set_difference / / find the difference set between two containers

5.6.1 set_intersection

Function Description:

  • Find the intersection of two containers

Function prototype:

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

    //Find the intersection of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the smaller of the two values to make room for the target container
	vTarget.resize(min(v1.size(), v2.size()));

	//Returns the iterator address of the last element of the destination container
	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;
}

Summary:

  • Find the ordered sequence of two sets of intersection
  • The target container needs to take a small value from the two containers to open up space
  • set_ The return value of intersection is the position of the last element in the intersection

5.6.2 set_union

Function Description:

  • Find the union of two sets

Function prototype:

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

    //Find the union of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the sum of the two containers to make room for the target container
	vTarget.resize(v1.size() + v2.size());

	//Returns the iterator address of the last element of the destination container
	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;
}

Summary:

  • Union of two ordered sets
  • The target container needs to add two containers to open up space
  • set_ The union return value is the position of the last element in the union set

5.6.3 set_difference

Function Description:

  • Find the difference set of two sets

Function prototype:

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

    //Find the difference set of two sets

    //Note: the two sets must be an ordered sequence

    //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;
	//Take the larger of the two values to make room for the target container
	vTarget.resize( max(v1.size() , v2.size()));

	//Returns the iterator address of the last element of the destination container
	cout << "v1 And v2 The difference set of is: " << 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 And v1 The difference set of is: " << 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;
}

Summary:

  • The two sets of difference sets must be ordered sequences
  • The target container needs to take a larger value from the two containers to open up space
  • set_ The return value of difference is the position of the last element in the difference set

This article is the dark horse programmer c + + tutorial handout, save and upload, only for the author's personal review and query
If there is infringement, please contact the author to delete

ps: finish this course in a work dormitory at 0:28 p.m. on February 24, 2022.

Keywords: C++

Added by Mortier on Wed, 23 Feb 2022 18:43:37 +0200