C++学习笔记(Ⅳ):C++提高编程

1 模板

1.1 模板的概念

建立通用的模板,提高代码复用性

1.2 函数模板

·c++还有一种利用模板的泛型编程

1. 语法

建立函数,其返回值类型和形参类型用虚拟类型代表

template

// 函数模板
template    //  声明一个模板,T是通用数据类型
void mySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

void test()
{
	int a = 10;
	int b = 20;
	// 1.自动类型推导
	mySwap(a, b);
	mySwap(a, b);
	// 2.显示指定类型
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
}

将类型参数化

2.注意事项

·自动类型推导:必须推导出一致的数据类型T

·模板必须确定出T的数据类型才可以使用

3.模板案例

C++学习笔记(Ⅳ):C++提高编程_第1张图片

// 交换函数模板
template
void myswap(T &a, T &b)
{
	int temp = a;
	a = b;
	b = temp;
}
// 排序算法
template    //  声明一个模板,T是通用数据类型
void mySort(T arr[],int len)
{
	for (int i = 0; i < len; i++)
	{
		int max = i;    // 认定最大值的下标
		for (int j = i+1; j < len; j++)
		{
			if (arr[max] < arr[j])   // 认定的最大值比便利出的值小
			{
				max = j;
			}
		}
		if (max != i)
		{
			myswap(arr[max], arr[i]);
		}
	}
}

void test()
{
	char chararr[] = "cabdjukadn";
	int num = sizeof(chararr) / sizeof(char);
	mySort(chararr, num);
	for (int i = 0; i < num; i++)
	{
		cout << chararr[i];
	}
	cout << endl;
}

4.普通函数与函数模板区别

·普通函数调用时可以发生隐式类型转换

·函数模板调用时,若利用自动类型推导,不会发生隐式类型转换

·若利用显示指定类型的方式,可以发生隐式类型转换(建议使用)

5.普通函数与函数模板的调用规则

·若函数模板和普通函数都可以实现,优先调用普通函数

·可通过空模板参数列表来强制调用函数模板

·函数模板可以发生重载

·若函数模板可以产生更好的匹配,优先调用函数模板

提供函数模板后不要提供普通函数,避免产生二义性

6.模板的局限性

模板不是万能的。无法实现自定义数据类型的通用化,需要利用模板重载具体化数据类型

// myCompare 为模板,进行重载
template<> bool myCompare(Person &a,Person &b)

1.3 类模板

1.语法

与函数模板大体一致

// 类模板
template
class Person
{
public:
	Person(Nametype name, Agetype age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	Nametype m_name;
	Agetype m_age;
};

2.类模板与函数模板的区别

·类模板中没有自动类型推导的方式

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

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

·普通成员函数一开始创建

·类模板中成员函数在调用时创建

4.类模板对象做函数参数

类模板实例化出的对象,向函数传参的方式:

·指定传入的类型:直接显示对象的数据类型

// 类模板对象做函数参数
template
class Person
{
public:
	Person(Nametype name, Agetype age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout << "name:" << this->m_name << endl;
		cout << "age:" << this->m_age << endl;
	}
	Nametype m_name;
	Agetype m_age;
};
// 1.指定传入类型
void printPerson1(Person&p)
{
	p.showPerson();
}
void test01()
{
	Personp("sun", 100);
	printPerson1(p);
}

·参数模板化:将对象中的参数变为模板进行传递

// 2.参数模板化
template
void printPerson2(Person&p)
{
	p.showPerson();
}
void test02()
{
	Personp("zhu", 99);
	printPerson2(p);
}

·整个类模板化:将这个对象类型模板化进行传递

// 3.整个类模板化
template
void printPerson3(T &p)
{
	p.showPerson();
}
void test03()
{
	Personp("sha", 90);
	printPerson3(p);
}

5.类模板与继承

·子类继承的父类为类模板时,子类在声明的时候,要指定父类T的类型,否则无法给子类分配内存

// 类模板与继承
template
class Base
{
	T m;
};
class son:public Base
{

};

·若需灵活指定父类T类型,子类需变为类模板

// 类模板与继承
template
class Base
{
	T m;
};
template
class son:public Base
{
	T1 obj;
};

6.类模板成员函数类外实现

类外实现时,类内只写函数声明

// 类模板成员函数类外实现
template
class Person
{
public:
	Person(T1 name, T2 age);
	void show();

	T1 m_name;
	T2 m_age;
};
// 构造函数的类外实现
template
Person::Person(T1 name, T2 age)
{
	this->m_name = name;
	this->m_age = age;
}
template
// 成员函数类外实现
void Person::show()
{
	cout << "姓名:" << this->m_name << "年龄:" << this->m_age << endl;
}

7.类模板分文件编写

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

void test()
{
	PersonP("time", 20);
	P.show();
}

类的声明在头文件中,类的实现在源文件中。此时主函数中调用上述代码会报错。

解决方法1:直接包含.cpp源文件

#include
using namespace std;
#include
#include"Person.cpp"

解决方法2:将声明和实现写到同一个文件中,更改后缀名为.hpp

#include"Person.hpp"

8.类模板与友元

全局函数类内实现:在类内声明友元

全局函数类外实现:提前让编译器得知全局函数的存在

// 让编译器提前获取类外函数
template
class Person;

template
void PrintPerson(Personp)
{
	cout << "姓名:" << p.m_name << "年龄:" << p.m_age << endl;
}
// 通过全局函数打印信息
template
class Person
{
	// 友元函数类外实现
	// 添加空模板的参数列表
	friend void PrintPerson<>(Personp);
public:
	Person(T1 name, T2 age)
	{
		this->m_name = name;
		this->m_age = age;
	}
private:
	T1 m_name;
	T2 m_age;
};

9.类模板案例

C++学习笔记(Ⅳ):C++提高编程_第2张图片

在.hpp文件中编写类模板

#pragma once
#include
using namespace std;
#include
// 通用数组类
template
class myArray
{
public:
	// 有参构造 参数 容量
	myArray(int capacity)
	{
		//cout << "有参构造调用" << endl;
		// 属性初始化
		this->m_Capacity = capacity;
		this->m_Size = 0;
		this->pAddress = new T[this->m_Capacity];    // 按照容量大小开辟堆区空间
	}
	// 拷贝构造(防止浅拷贝)
	myArray(const myArray& arr)
	{
		//cout << "拷贝构造调用" << endl;
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;        // 指针不能直接赋值,否则会产生浅拷贝
		// 深拷贝
		this->pAddress = new T[arr.m_Capacity];     
		// 拷贝arr中数据
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}
	myArray& operator=(const myArray& arr)
	{
		//cout << "operator=调用" << endl;
		// 先判断堆区是否有数据,若有先释放
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_Size = 0;
		}
		// 深拷贝
		this->m_Capacity = arr.m_Capacity;
		this->m_Size = arr.m_Size;
		this->pAddress = new T[arr.m_Capacity];
		// 拷贝arr中数据
		for (int i = 0; i < this->m_Size; i++)
		{
			this->pAddress[i] = arr.pAddress[i];
		}
	}
	// 尾插法
	void pushBack(const T & val)
	{
		// 判断容量是否等于大小
		if (this->m_Capacity == this->m_Size)
		{
			return;
		}
		this->pAddress[this->m_Size] = val;   // 在数组末尾插入数据
		this->m_Size++;    // 更新数组大小
	}
	// 尾删法
	void popBack()
	{
		// 让用户无法访问末尾
		if (this->m_Size==0)
		{
			return;
		}
		this->m_Size--;
	}
	// 通过下标访问数组元素
	T& operator[](int index)       // operator重载运算符[]
	{
		return this->pAddress[index];
	}
	// 返回数组容量
	int getCapacity()
	{
		return this->m_Capacity;
	}
	// 返回数组大小
	int getSize()
	{
		return this->m_Size;
	}
	
	// 析构函数
	// 释放堆区空间
	~myArray()
	{
		//cout << "析构函数调用" << endl;
		if (this->pAddress != NULL)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;           // 置空防止野指针
		}
	}
private:
	T * pAddress;       // 指针指向堆区开辟的真实数组
	int m_Capacity;     // 数组容量
	int m_Size;         // 数组大小
};

其中:构造函数为初始化、拷贝构造防止浅拷贝、operator=重载操作符防止浅拷贝、析构函数清空堆区内容。

源文件

#include
using namespace std;
#include
#include"myArray.hpp"
void printIntArray(myArray&arr)
{
	for (int i = 0; i < arr.getSize(); i++)
	{
		cout << arr[i] << endl;
	}
}
void test()
{
	myArrayarr1(5);
	for (int i = 0; i < 5; i++)
	{
		arr1.pushBack(i);
	}
	printIntArray(arr1);
	cout << "arr1的容量" << arr1.getCapacity() << endl;
	cout << "arr1的大小" << arr1.getSize() << endl;
	
	myArrayarr2(arr1);
	printIntArray(arr2);
	arr2.popBack();
	cout << "arr2尾删后的容量" << arr2.getCapacity() << endl;
	cout << "arr12尾删后的大小" << arr2.getSize() << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}

2 STL初始

2.1 STL基本概念

1.概念:STL(standard template library,标准模板库)

2.STL从广义上分为:容器、算法、迭代器

3.容器和算法间通过迭代器连接

2.2 STL组件

1.容器:各类数据结构

2.算法:各类常用算法

3.迭代器:容器与算法间的桥梁

4.仿函数:行为类似函数

5.适配器:修饰容器或仿函数或迭代器接口

6.空间配置器:空间配置与管理

2.3 STL容器、算法及迭代器

1.容器分为序列式容器(强调值的排序,序列式容器中每个元素均有固定位置)与关联式容器(二叉树结构,各元素间没有严格物理上的顺序关系)

2.算法分为质变算法(运算期间会更改区间元素内容)和非质变算法(运算期间不会更改区间元素内容)

3.迭代器种类

C++学习笔记(Ⅳ):C++提高编程_第3张图片

2.4 容器算法、迭代器初识

1.vector存放内置数据类型

#include
using namespace std;
#include
#include
#include
// vector容器存放内置数据类型
void myPrint(int val)
{
	cout << val << endl;
}
void test()
{
	// 创建vector容器,可认为是数组
	vector v;
	// 向容器中插入数据
	v.push_back(10);
	v.push_back(1200);
	v.push_back(120);
	
	// 第一种遍历方式
	// 通过迭代器访问容器中的数据
	vector::iterator itBegin = v.begin();    // 起始迭代器,指向容器中首个元素
	vector::iterator itEnd = v.end();        // 结束迭代器,指向容器中末尾元素的下一个位置
	while (itBegin != itEnd)
	{
		cout << *itBegin << endl;
		itBegin++;
	}
	// 第二种遍历方式
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}
	// 第三种遍历方式,利用遍历算法
	for_each(v.begin(), v.end(), myPrint);
}

2.vector存放自定义数据类型

// vector容器存放自定义数据类型
class Person
{
public:
	Person(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
	string name;
	int age;
};

void test()
{
	// 创建vector容器
	vector v;
	Person p1("a", 10);
	Person p2("b", 20);
	Person p3("c", 30);

	// 向容器中添加数据
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	
	// 通过迭代器访问容器中的数据
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" <<(*it).name<< " 年龄:"<<(*it).age << endl;
		// 以下相同
		//cout << "姓名:" << it->name<< " 年龄:" << it->age << endl;
	}
}
// 存放自定义数据类型的指针
void test01()
{
	// 创建vector容器
	vector v;
	Person p1("a", 10);
	Person p2("b", 20);
	Person p3("c", 30);

	// 向容器中添加数据
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);

	// 遍历
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" << (*it)->name << " 年龄:" << (*it)->age << endl;
	}
}

3.vector容器嵌套

// vector容器嵌套
void test()
{
	// 创建vector容器
	vector> v;
	// 创建内层容器
	vector v1;
	vector v2;
	vector v3;
	for (int i = 0; i < 4; i++)
	{
		v1.push_back(i + 1);
		v2.push_back(i + 2);
		v3.push_back(i + 3);
	}
	// 创建外层容器
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	// 通过迭代器访问容器中的数据
	for (vector>::iterator it = v.begin(); it != v.end(); it++)
	{
		for (vector::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
		{
			cout << *vit;
		}
		cout << endl;

	}
}

3 STL常用容器

3.1 string容器

1.string概念

string本质上是个类,是一个char*型的容器。类内提供了多种成员方法

2.string构造函数

string();   默认构造

string(const char* s);    使用字符串初始化

string(const string str);   使用一个string对象初始化另一个string对象

string(int n ,char c);          使用n个字符串c初始化

3.string赋值操作

C++学习笔记(Ⅳ):C++提高编程_第4张图片

 常用前三种方式赋值

    // 方法1
	string str1;
	str1 = "hello";

	// 方法2
	string str2;
	str2 = str1;

	// 方法3
	string str3;
	str3 = 'a';

	// 方法4
	string str4;
	str4.assign("hello");

	// 方法5
	string str5;
	str5.assign("hello", 4);

	// 方法6
	string str6;
	str6.assign(str5);

	// 方法7
	string str7;
	str7.assign(10, '7');

4.string字符串拼接

C++学习笔记(Ⅳ):C++提高编程_第5张图片

	// 方法1
	string str1 = "hello";
	str1 += "world";

	// 方法2
	string str2 = "!";
	str1 += str2;

	// 方法3
	string str3 = "hello";
	str3.append("world");

	// 方法4
	string str4 = "hello";
	str4.append("hello",4);

	// 方法5
	string str5 = "hello";
	str5.append(str2);

	// 方法6
	string str6;
	str6.append(str5,0,3);

5.string查找和替换

C++学习笔记(Ⅳ):C++提高编程_第6张图片

	// 查找
	// 方法1
	string str1 = "hello";
	str1.find("l");   // 若存在返回1,否则返回-1

	// 方法2
	str1.rfind("l");   // rfind从右往左查,find查找顺序相反

	// 替换
	str1.replace(1,3,"11");

6.string字符串比较

C++学习笔记(Ⅳ):C++提高编程_第7张图片

字符串以ASCii大小进行比较,相等返回0,大于返回1,小于返回-1

	// 字符串比较
	string str1 = "hello";
	string str2 = "hello";
	if (str1.compare(str2) == 0)
	{
		cout << "相等" << endl;
	}

7.string存取

C++学习笔记(Ⅳ):C++提高编程_第8张图片

	// 字符串存取
	string str = "hello world";
	// 方法1:通过[]访问单个字符
	for (int i = 0; i < str.size(); i++)

	{
		cout << str[i] << endl;
	}
	// 方法2通过at方式
	for (int i = 0; i < str.size(); i++)
	{
		cout << str.at(i) << endl;
	}

8.string插入和删除

C++学习笔记(Ⅳ):C++提高编程_第9张图片

	// 字符串插入与删除
	string str = "hello world";
	
	str.insert(1, "11");   // 插入

	str.erase(1, 2);      // 删除

9.string子串

	// 字符串子串获取
	string str = "hello world";
	
	string subStr = str.substr(1, 3);

3.2 vector容器

1.vector概念

vector与数组类似,称为单端数组;不同于数组是静态空间,vector可以动态扩展(寻找更大的内存空间,将源数据拷贝至新空间,并释放原空间)

C++学习笔记(Ⅳ):C++提高编程_第10张图片

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

2.vector构造函数

创建vector容器

C++学习笔记(Ⅳ):C++提高编程_第11张图片

	vector v1;     // 无参构造

	vector v2(v1.begin(), v1.end());   // 通过区间方式进行构造

	vector v3(10, 100);    // n个elem方式构造

	vector v4(v3);         // 拷贝构造

3.vector赋值操作

C++学习笔记(Ⅳ):C++提高编程_第12张图片

	// 无参构造
	vector v1;     
    // operator=
	vector v2;
	v2 = v1;         
	// assign
	vector v3;        
	v3.assign(v1.begin(), v1.end());   
	// n个elem赋值
	vector v4;  
	v4.assign(10, 100);

4.vector容量和大小

C++学习笔记(Ⅳ):C++提高编程_第13张图片

5.vector插入和删除

C++学习笔记(Ⅳ):C++提高编程_第14张图片

6.vector数据存取

7.vector互换容器

swap可以收缩空间

	vector v;  
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	vector(v).swap(v);
	cout << v.capacity() << endl;
	cout << v.size() << endl;

8.vector预留空间

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

3.3 deque容器

1.deque基本概念

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

C++学习笔记(Ⅳ):C++提高编程_第15张图片

2.deque构造函数

C++学习笔记(Ⅳ):C++提高编程_第16张图片

3.deque赋值操作

C++学习笔记(Ⅳ):C++提高编程_第17张图片

4.deque大小操作

C++学习笔记(Ⅳ):C++提高编程_第18张图片

5.deque插入和删除

C++学习笔记(Ⅳ):C++提高编程_第19张图片

C++学习笔记(Ⅳ):C++提高编程_第20张图片

6.deque数据存取

C++学习笔记(Ⅳ):C++提高编程_第21张图片

7.deque排序

需包含算法头文件

对于支持随机访问的迭代器的容器(vector),都可利用sort算法直接对其排序。

3.4 案例-评委打分

// 选手类
class Person
{
public:
	Person(string name, int score)
	{
		this->m_name = name;
		this->m_score = score;
	};
	string m_name;
	int m_score;
};
// 创建选手
void creatPerson(vector &v)
{
	string nameSeed = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
		string name = "选手";
		name += nameSeed[i];
		int score = 0;
		
		Person p(name, score);
		// 将创建的person对象,放入到容器中 
		v.push_back(p);
	}
}
// 打分函数
void setScore(vector &v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		deque d;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 41 + 60;
			d.push_back(score);
		}
		// 排序
		sort(d.begin(), d.end());
		// 去除最高与最低分
		d.pop_back();
		d.pop_front();
		// 取平均分
		int sum = 0;
		for (deque::iterator dit = d.begin(); dit != d.end(); dit++)
		{
			sum += *dit;
		}
		int avg = sum / d.size();
		// 赋值给选手
		it->m_score = avg;
	}
}
// 显示得分
void showScore(vector &v)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << "姓名:" << it->m_name << " 平均分:"<< it->m_score << endl;
	}
}

3.5 stack容器

1.概念

stack是一种先进后出的数据结构,只有一个出口。栈不允许有遍历行为

C++学习笔记(Ⅳ):C++提高编程_第22张图片

2.常用接口

C++学习笔记(Ⅳ):C++提高编程_第23张图片

C++学习笔记(Ⅳ):C++提高编程_第24张图片

C++学习笔记(Ⅳ):C++提高编程_第25张图片

3.6 queue容器

1.queue概念

queue是一种先进先出的数据接口,只有队头和队尾才可被访问,不可遍历。

C++学习笔记(Ⅳ):C++提高编程_第26张图片

2.queue常用接口

 

C++学习笔记(Ⅳ):C++提高编程_第27张图片

C++学习笔记(Ⅳ):C++提高编程_第28张图片

3.7 list容器

1.list概念

·将数据进行链式存储

·链表是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。

·链表由一系列结点组成,结点一个是存储数据元素的数据域,另一个是村查下一个结点地址都指针域

·STL中的链表是一个双向循环链表

·可以对任意位置进行快速插入或删除元素,但遍历速度没有数组快,且占用空间比数组大

C++学习笔记(Ⅳ):C++提高编程_第29张图片

 链表中的迭代器只支持前移和后移,属于双向迭代器

2.list构造函数

C++学习笔记(Ⅳ):C++提高编程_第30张图片

3.list赋值和交换

C++学习笔记(Ⅳ):C++提高编程_第31张图片

4.list大小操作

C++学习笔记(Ⅳ):C++提高编程_第32张图片

5.list插入和删除

C++学习笔记(Ⅳ):C++提高编程_第33张图片

6.list数据存取

list不能用[]与at方式访问元素,迭代器不支持随机访问

7.list反转和排序

8.排序案例

// 类定义
class Person
{
public:
	Person(string name,int age,int height)
	{
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
	}
	string m_name;
	int m_age;
	int m_height;
};
// 排序规则
bool comparePerson(Person &p1, Person &p2)
{
	if (p1.m_age == p2.m_age)
	{
		return p1.m_height > p2.m_height;
	}
	return p1.m_age < p2.m_age;
}
void test()
{
	list L;
	// 准备数据
	Person p1("刘备", 35, 175);
	Person p2("曹操", 45, 180);
	Person p3("孙权", 40, 170);
	Person p4("张飞", 25, 190);
	Person p5("关羽", 35, 160);
	Person p6("赵云", 35, 200);
	// 插入数据
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	L.push_back(p6);
	for (list::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名:" << (*it).m_name << " 年龄:" << (*it).m_age << " 身高:" << (*it).m_height<< endl;
	}
	// 排序
	cout << "排序后:" << endl;
	L.sort(comparePerson);
	for (list::iterator it = L.begin(); it != L.end(); it++)
	{
		cout << "姓名:" << (*it).m_name << " 年龄:" << (*it).m_age << " 身高:" << (*it).m_height << endl;
	}
}

3.8 set/multiset容器

1.set基本概念

·所有元素在插入时被自动排序

·属于关联式容器,底层结构用二叉树实现

·不允许有重复元素

2.set构造和赋值

C++学习笔记(Ⅳ):C++提高编程_第34张图片

3.set大小和交换

C++学习笔记(Ⅳ):C++提高编程_第35张图片

4.set插入和删除

C++学习笔记(Ⅳ):C++提高编程_第36张图片

5.set查找和统计

6.set和multiset区别

C++学习笔记(Ⅳ):C++提高编程_第37张图片

7.pair对组创建

成对出现的数据,利用对组可以返回两个数据

// 对组的创建
	pairp1("tom", 20);
	cout << p1.first << p1.second << endl;
	pairp2 = make_pair("jerry", 30);
	cout << p2.first << p2.second << endl;

8.set容器排序

可以利用仿函数改变排序规则

·内置数据类型排序

// 仿函数
class mycompare
{
public:
	bool operator()(int v1,int v2)   // 第一个()代表重载符,第二个()代表函数参数列表
	{
		return v1 > v2;
	}
};
void test()
{
	sets1;
	s1.insert(10);
	s1.insert(20);
	s1.insert(40);
	s1.insert(30);
	for (set::iterator it = s1.begin(); it != s1.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}

·自定义数据类型排序

class Person
{
public:
	Person(string name, int age)
	{
		this->m_name = name;
		this->m_age = age;
	}
	string m_name;
	int m_age;
};
class mycompare
{
public:
	bool operator()(const Person &p1, const Person &p2)   // 第一个()代表重载符,第二个()代表函数参数列表
	{
		return p1.m_age > p2.m_age;
	}
};
void test()
{
	// 自定义数据类型要指定排序规则
	sets;
	Person p1("tom", 24);
	Person p2("jarry", 34);
	Person p3("luffy", 25);
	Person p4("zoro", 14);
	Person p5("sam", 55);

	s.insert(p1);
	s.insert(p2);
	s.insert(p3);
	s.insert(p4);
	s.insert(p5);

	for (set::iterator it = s.begin(); it != s.end(); it++)
	{
		cout << it->m_name <<  " " << it->m_age <

3.9 map/multimap容器

1.map概念

·map中所有元素都是pair

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

·所有元素都会根据元素的键值自动排序

·map/multimap属于关联式容器,底层结构式二叉树实现

·可以根据key值快速找到value值

·map中不允许有重复key值元素

2.map构造和赋值

C++学习笔记(Ⅳ):C++提高编程_第38张图片

 

数据插入时要使用对组

3.map大小和交换

C++学习笔记(Ⅳ):C++提高编程_第39张图片

4.map插入和删除

C++学习笔记(Ⅳ):C++提高编程_第40张图片

5.map查找和统计

6.map容器排序

利用仿函数可以改变排序规则

3.10 案例-员工分组

C++学习笔记(Ⅳ):C++提高编程_第41张图片

// 创建员工类
class Worker
{
public:
	string m_name;
	int m_salary;
};
void creatWorker(vector &v)
{
	string workerName = "ABCDEFGHIJ";
	for (int i = 0; i < 10; i++)
	{
		Worker worker;
		worker.m_name = workerName[i];
		worker.m_salary = rand()%10000 + 10000;   // 10000--19999
		v.push_back(worker);
	}
}
// 员工分组
void setGroup(vector &v, multimap &m)
{
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		// 产生随机部门编号
		int deptId = rand() % 3;   // 0 1 2
		m.insert(make_pair(deptId, *it));
	}
}
void showWorker(multimap &m)
{
	cout << "0号部门成员:" << endl;
	multimap::iterator pos = m.find(0);
	int count = m.count(0);
	int index = 0;
	for (; pos != m.end() && index < count; pos++,index++)
	{
		cout << "姓名:" << pos->second.m_name << " 工资:" << pos->second.m_salary << endl;
	}

	cout << "1号部门成员:" << endl;
	pos = m.find(1);
	count = m.count(1);
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名:" << pos->second.m_name << " 工资:" << pos->second.m_salary << endl;
	}

	cout << "2号部门成员:" << endl;
	pos = m.find(2);
	count = m.count(2);
	index = 0;
	for (; pos != m.end() && index < count; pos++, index++)
	{
		cout << "姓名:" << pos->second.m_name << " 工资:" << pos->second.m_salary << endl;
	}
}

4 STL函数对象

4.1 函数对象

1.函数对象概念

本质上是一个类 

2.函数对象使用

C++学习笔记(Ⅳ):C++提高编程_第42张图片

// 仿函数
// 可以像普通函数一样调用,可以有参数值与返回值
class myAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};
void test01()
{
	myAdd a;
	cout << a(10, 10) << endl;
}
// 函数对象可以有自己的状态
class myPrint
{
public:
	myPrint()
	{
		this->count = 0;
	}
	void operator()(string test)
	{
		cout << test << endl;
		this->count++;
	}
	int count;   // 记录内部状态

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

4.2 谓词

1.概念

C++学习笔记(Ⅳ):C++提高编程_第43张图片

2.一元谓词

// 一元谓词
// 仿函数
class GreaterFive
{
public:
	bool operator()(int val)
	{
		return val > 5;
	}
};
void test()
{
	vector v;
	for (int i = 0; i <10 ; i++)
	{
		v.push_back(i);
	}
	// 查找是否存在大于5的数字
	vector::iterator it = find_if(v.begin(), v.end(), GreaterFive());

3.二元谓词

// 二元谓词
// 仿函数
class mycompare
{
public:
	bool operator()(int v1,int v2)
	{
		return v1 > v2;
	}
};
void test()
{
	vector v;
	v.push_back(10);
	v.push_back(30);
	v.push_back(20);
	v.push_back(40);
	v.push_back(50);

	sort(v.begin(), v.end(), mycompare());
	for (vector::iterator it = v.begin(); it != v.end(); it++)
	{
		cout << *it << endl;
	}
}

4.3 内建函数对象

1.内建函数对象

需要添加头文件functional

2.算术仿函数

实现四则运算

C++学习笔记(Ⅳ):C++提高编程_第44张图片

	// 一元仿函数
	negate n;
	cout << n(50) << endl;
	// 二元仿函数
	plus p;
	cout << p(10, 20) << endl;

3.关系仿函数

C++学习笔记(Ⅳ):C++提高编程_第45张图片

4.逻辑仿函数

C++学习笔记(Ⅳ):C++提高编程_第46张图片

5 STL常用算法

5.1 常用遍历算法

·算法头文件:algorithm、functional、numeric

1.for_each

C++学习笔记(Ⅳ):C++提高编程_第47张图片

2.transform

搬运容器到另一个容器中,搬运前需要给目标容器开辟空间

C++学习笔记(Ⅳ):C++提高编程_第48张图片

5.2 常用查找算法

1.find

按值查找元素

C++学习笔记(Ⅳ):C++提高编程_第49张图片

若查找自定义数据类型,需在类中重载==运算符

2.find_if

按条件查找元素

C++学习笔记(Ⅳ):C++提高编程_第50张图片

3.adjacent_find

查找相邻重复元素

C++学习笔记(Ⅳ):C++提高编程_第51张图片

4.binary_search

查找指定元素是否存在

C++学习笔记(Ⅳ):C++提高编程_第52张图片

5.count

统计元素个数

C++学习笔记(Ⅳ):C++提高编程_第53张图片

6.count_if

按条件统计元素个数

C++学习笔记(Ⅳ):C++提高编程_第54张图片

5.3 常用排序算法

1.sort

C++学习笔记(Ⅳ):C++提高编程_第55张图片 

2.random_shuffle

C++学习笔记(Ⅳ):C++提高编程_第56张图片 

3.merge

C++学习笔记(Ⅳ):C++提高编程_第57张图片

4.reverse

C++学习笔记(Ⅳ):C++提高编程_第58张图片

5.4 常用拷贝和替换算法

1.copy

C++学习笔记(Ⅳ):C++提高编程_第59张图片 

2.replace

3.replace_if

C++学习笔记(Ⅳ):C++提高编程_第60张图片

4.swap

C++学习笔记(Ⅳ):C++提高编程_第61张图片

5.5 常用算术生成算法

1.accumulate

C++学习笔记(Ⅳ):C++提高编程_第62张图片

2.fill

C++学习笔记(Ⅳ):C++提高编程_第63张图片

5.6 常用集合算法

1.set_intersection

C++学习笔记(Ⅳ):C++提高编程_第64张图片

2.set_union

C++学习笔记(Ⅳ):C++提高编程_第65张图片

3.set_difference

C++学习笔记(Ⅳ):C++提高编程_第66张图片

 目标容器开辟空间需要从两个容器取较大值

你可能感兴趣的:(C++,c++,学习,开发语言)