C++知识点梳理 | 自用

文章目录

前言

小记:2024年2月29日至2024年3月19日,在B站看了比黑马的《黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难》,根据课件总结此C++知识点梳理,以备后续复习使用。
黑马程序员的这个老师讲的非常细致,每节课都会开头简介和结尾总结,感谢黑马的老师。因为刚学完C语言,第一部分基础入门过了一遍课件就懂了,基础部分大体与C语言差不多,所以基础入门的笔记只记了C++不一样的地方。如果学过数据结构的话,提高部分的容器和算法学起来会非常轻松,学习一下用法就够了。
2.29-3.19

一、基础入门:

1. 字符型

字符型变量用于显示单个字符,char ch = ‘a’;
字符串:
C风格字符串: char 变量名[] = “字符串值”
C++风格字符串: string 变量名 = “字符串值”,需要加入头文件#include

2. 布尔类型 bool(1个字节)

true — 真(本质是1)
false — 假(本质是0)

3. 输入输出

数据的输入:cin >> 变量;
数据的输出:cout<<” ” <<” ”<<endl;

4. 三目运算符

表达式1 ? 表达式2 :表达式3 //C++中三目运算符返回的是变量,可以继续赋值

int a = 10;
int b = 20;
(a > b ? a : b) = 100;
cout << "a = " << a << endl;    //a=10
cout << "b = " << b << endl    //b=100,赋值给了比较之后被执行表达式的变量

5.const修饰指针

int main() 
{
int a = 10;
int b = 10;
//const修饰的是指针,指针指向可以改,指针指向的值不可以更改
const int * p1 = &a;
p1 = &b; //正确
//*p1 = 100; 报错
//const修饰的是常量,指针指向不可以改,指针指向的值可以更改
int * const p2 = &a;
//p2 = &b; //错误
*p2 = 100; //正确
//const既修饰指针又修饰常量
const int * const p3 = &a;
//p3 = &b; //错误
//*p3 = 100; //错误
system("pause");
return 0;
} 

6. 结构体数组

struct 结构体名 数组名[元素个数] = { {} , {} , … {} }
定义结构体时的关键字是struct,不可省略;创建结构体变量时,关键字struct可以省略。

二、核心编程(面对对象)

1. 内存分区模型

C++程序在执行时,将内存大方向划分为4个区域(不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程)
代码区:存放函数体的二进制代码,由操作系统进行管理的(共享和只读)
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收(利用new开辟内存)

1.1 new操作符

利用new操作符在堆区开辟数据,释放利用操作符 delete
语法: new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针

2. 引用

本质:是一个指针常量

int a = 10;
//自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改
int& ref = a;
ref = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;

作用: 给变量起别名
语法: 数据类型 &别名 = 原名
注意:引用必须初始化,引用在初始化后,不可以改变

2.1 引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参

2.2引用做函数返回值

作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值

2.3 常量引用

作用:常量引用主要用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
//int& ref = 10; 引用本身需要一个合法的内存空间,因此这行错误
//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
const int& ref = 10;

3. 函数提高

3.1 函数默认参数

在C++中,函数的形参列表中的形参是可以有默认值的。
语法: 返回值类型 函数名 (参数= 默认值){} //1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
//2. 如果函数声明有默认值,函数实现的时候就不能有默认参数

3.2 函数占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法: 返回值类型 函数名 (数据类型){}

3.3 函数重载

作用:函数名可以相同,提高复用性
函数重载满足条件:
同一个作用域下
函数名称相同
函数参数类型不同 或者 个数不同 或者 顺序不同
注意: 函数的返回值不可以作为函数重载的条件

4. 类和对象

C++面向对象的三大特性为:封装、继承、多态

4.1 封装

封装的意义:
①在设计类的时候,属性和行为写在一起,表现事物
语法: class 类名{ 访问权限: 属性 / 行为 };
②类在设计时,可以把属性和行为放在不同的权限下,加以控制
//公共权限 public 类内可以访问 类外可以访问
//保护权限 protected 类内可以访问 类外不可以访问
//私有权限 private 类内可以访问 类外不可以访问
(struct 默认权限为公共 class 默认权限为私有)

4.2 对象的初始化和清理

对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供。编译器提供的构造函数和析构函数是空实现。

4.2.1 构造函数:

主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

①类名(){}

  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

②两种分类方式:
按参数分为: 有参构造和无参构造(无参又称为默认构造函数)
按类型分为: 普通构造和拷贝构造(拷贝构造Person(const Person& p))

③三种调用方式:

//3.1 括号法,常用
Person p1(10);
//注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声
//Person p2();
//3.2 显式法
Person p2 = Person(10);
Person p3 = Person(p2);
//Person(10)单独写就是匿名对象 当前行结束之后,马上析构
//3.3 隐式转换法
Person p4 = 10; // Person p4 = Person(10);
Person p5 = p4; // Person p5 = Person(p4);
//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
//Person p5(p4);

④ 拷贝构造函数调用时机
C++中拷贝构造函数调用时机通常有三种情况
使用一个已经创建完毕的对象来初始化一个新对象
值传递的方式给函数参数传值
以值方式返回局部对象

⑤构造函数调用规则
默认情况下,c++编译器至少给一个类添加3个函数
1.默认构造函数(无参,函数体为空)
2.默认析构函数(无参,函数体为空)
3.默认拷贝构造函数,对属性进行值拷贝
构造函数调用规则如下:
如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
如果用户定义拷贝构造函数,c++不会再提供其他构造函数

⑥深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作
如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的重复释放堆区问题

4.2.2 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

~类名(){}
6. 析构函数,没有返回值也不写void
7. 函数名称与类名相同,在名称前加上符号 ~
8. 析构函数不可以有参数,因此不可以发生重载
9. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

4.2.3初始化列表

初始化列表语法,用来初始化属性
语法: 构造函数():属性1(值1),属性2(值2)… {}

//传统方式初始化
//Person(int a, int b, int c) {
// m_A = a;
// m_B = b;
// m_C = c;
//}
//初始化列表方式初始化
Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
4.2.4类对象作为类成员

当类中成员是其他类对象时,我们称该成员为 对象成员
构造的顺序是 :先调用对象成员的构造,再调用本类构造
析构顺序与构造相反

4.2.5静态成员

①静态成员变量:
所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化
②静态成员函数:
所有对象共享同一个函数
静态成员函数只能访问静态成员变量

4.3 C++对象模型和this指针

4.3.1 成员变量和成员函数分开存储

在C++中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上

4.3.2 this指针

this指针指向被调用的成员函数所属的对象,this指针是隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用即可
this指针的用途:
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this

4.3.3 空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性

4.3.4 const修饰成员函数

常函数:成员函数后加const后我们称为这个函数为常函数;常函数内不可以修改成员属性;成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:声明对象前加const称该对象为常对象;常对象只能调用常函数

4.4友元

友元的目的就是让一个函数或者类 访问另一个类中私有成员,关键字为 friend 三种实现:全局函数做友元,类做友元,成员函数做友元

4.5 运算符重载

对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型
返回类型 operator运算符()

4.5.1 加号运算符重载

作用:实现两个自定义数据类型相加的运算

4.5.2 左移运算符重载

作用:可以输出自定义数据类型

4.5.3 递增运算符重载

作用: 通过重载递增运算符,实现自己的整型数据
前置递增返回引用,后置递增返回值

4.5.4 赋值运算符重载

c++编译器至少给一个类添加4个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性进行值拷贝
  4. 赋值运算符 operator=, 对属性进行值拷贝
    如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题
4.5.6 函数调用运算符重载

函数调用运算符 () 也可以重载
由于重载后使用的方式非常像函数的调用,因此称为仿函数
仿函数没有固定写法,非常灵活

4.6 继承

面向对象三大特性之一, 利用继承的技术,减少重复代码
继承的语法: class 子类 : 继承方式 父类

4.6.1 继承方式

公共继承,保护继承,私有继承
父类中私有成员也是被子类继承下去了,只是由编译器给隐藏后访问不到
在这里插入图片描述

4.6.2 继承同名成员处理方式

访问子类同名成员 直接访问即可
访问父类同名成员 需要加作用域
静态成员和非静态成员出现同名,处理方式一致

  1. 子类对象可以直接访问到子类中同名成员
  2. 子类对象加作用域可以访问到父类同名成员
  3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
4.6.3 多继承语法

语法: class 子类 :继承方式 父类1 , 继承方式 父类2…
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C++实际开发中不建议用多继承

4.6.4 菱形继承

继承前加virtual关键字后,变为虚继承
此时公共的父类Animal称为虚基类 菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义
利用虚继承可以解决菱形继承问题(原理:虚基类指针)

4.7 多态

C++面向对象三大特性之一

4.7.1多态分为两类

静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名,数地址早绑定 - 编译阶段确定函数地址
动态多态: 派生类和虚函数实现运行时多态,函数地址晚绑定 - 运行阶段确定函数地址
多态满足条件:有继承关系;子类重写父类中的虚函数
多态使用条件:父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
多态的优点: 代码组织结构清晰;可读性强;利于前期和后期的扩展以及维护。C++开发提倡利用多态设计程序架构。

4.7.2 纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容,因此可以将虚函数改为纯虚函数。当类中有了纯虚函数,这个类也称为抽象类
纯虚函数语法: virtual 返回值类型 函数名 (参数列表)= 0 ;
抽象类特点:无法实例化对象;子类必须重写抽象类中的纯虚函数,否则也属于抽象类

4.7.3虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码.
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:可以解决父类指针释放子类对象;都需要有具体的函数实现
虚析构和纯虚析构区别:如果是纯虚析构,该类属于抽象类,无法实例化对象 虚析构语法:
virtual ~类名(){}
纯虚析构语法:(类内声明类外初始化)
virtual ~类名() = 0;
类名::~类名(){}

  • 总结:
  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
  2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
  3. 拥有纯虚析构函数的类也属于抽象类

5.文件操作

C++中对文件操作需要包含头文件 < fstream >
文件类型分为两种:

  1. 文本文件 - 文件以文本的ASCII码形式存储在计算机中
  2. 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
    操作文件的三大类:
    1.ofstream:写操作
    2.ifstream: 读操作
    3.fstream : 读写操作
  • 操作流程:
  1. 包含头文件
    #include

  2. 创建流对象
    ofstream ofs; | ifstream ofs; | fstream ofs;

  3. 打开文件
    ofs.open(“文件路径”,打开方式);
    读文件需要判断文件是否打开成功。
    在这里插入图片描述

  4. 读/写数据
    4.1文件
    ofs << “写入的数据”;
    四种读数据方式:

//第一种方式
//char buf[1024] = { 0 };
//while (ifs >> buf)
//{
// cout << buf << endl;
//}
//第二种
//char buf[1024] = { 0 };
//while (ifs.getline(buf,sizeof(buf)))
//{
// cout << buf << endl;
//}
//第三种
//string buf;
//while (getline(ifs, buf))
//{
// cout << buf << endl;
//}
char c;
while ((c = ifs.get()) != EOF)
{
cout << c;
} 

4.2二进制文件
文件输出流对象 可以通过write函数,以二进制方式写数据
函数原型 : ostream& write(const char * buffer,int len);
文件输入流对象 可以通过read函数,以二进制方式读数据
函数原型: istream& read(char *buffer,int len); 5. 关闭文件
ofs.close(); | ifs.close();

三、提高编程

1 模板

C++另一种编程思想称为 泛型编程 ,主要利用的技术就是模板。函数模板和类模板。

1.1 函数模板

函数模板作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。
使用函数模板有两种方式:自动类型推导、显示指定类型
语法:
template
函数声明或定义
解释:
template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母
注意事项:
自动类型推导,必须推导出一致的数据类型T,才可以使用
模板必须要确定出T的数据类型,才可以使用

1.1.1普通函数与函数模板的区别

普通函数与函数模板区别:
普通函数调用时可以发生自动类型转换(隐式类型转换)
函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
如果利用显示指定类型的方式,可以发生隐式类型转换
(建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T)
调用规则如下:

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以产生更好的匹配,优先调用函数模板
    (既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性)
1.1.2模板的局限性

提供模板的重载,可以为这些特定的类型提供具体化的模板
具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型

1.2类模板

类模板作用:建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
语法:
template

解释:
template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母

1.2.1类模板与函数模板区别

类模板与函数模板区别主要有两点:

  1. 类模板没有自动类型推导的使用方式
  2. 类模板在模板参数列表中可以有默认参数
1.2.2类模板中成员函数创建时机

类模板中成员函数和普通类中成员函数创建时机是有区别的:
普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才创建

1.2.3类模板对象做函数参数

一共有三种传入方式:
1.指定传入的类型 — 直接显示对象的数据类型(推荐使用)
2.参数模板化 — 将对象中的参数变为模板进行传递
3.整个类模板化 — 将这个对象类型 模板化进行传递

1.2.4类模板与继承

当类模板碰到继承时,需要注意一下几点:
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
如果不指定,编译器无法给子类分配内存
如果想灵活指定出父类中T的类型,子类也需变为类模板

1.2.5类模板成员函数类外实现

类模板中成员函数类外实现时,需要加上模板参数列表

//类模板中成员函数类外实现
template<class T1, class T2>
class Person {
public:
//成员函数类内声明
Person(T1 name, T2 age);
void showPerson();
public:
T1 m_Name;
T2 m_Age;
};
//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
//成员函数 类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
} 
1.2.6类模板分文件编写

问题:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

1.2.7类模板与友元

全局函数类内实现 - 直接在类内声明友元即可
全局函数类外实现 - 需要提前让编译器知道全局函数的存在

2. STL

STL(Standard Template Library,标准模板库)
STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)
容器和算法之间通过迭代器进行无缝连接。
STL 几乎所有的代码都采用了模板类或者模板函数
STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

  1. 容器:置物之所也
    STL容器就是将运用最广泛的一些数据结构实现出来
    常用的数据结构:数组, 链表,树, 栈, 队列, 集合, 映射表 (如vector、list、deque、set、map)等
    这些容器分为序列式容器和关联式容器两种:
    序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
    关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

  2. 算法:问题之解法也
    有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)
    算法分为:质变算法和非质变算法。
    质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等
    非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值(如sort、find、copy、for_each)等等

  3. 迭代器:容器和算法之间粘合剂
    提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。迭代器使用非常类似于指针。
    迭代器种类:
    在这里插入图片描述

  4. 仿函数:行为类似函数,可作为算法的某种策略。

  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。

  6. 空间配置器:负责空间的配置与管理。

3.STL- 常用容器

3.1 string容器

本质:string是C++风格的字符串,而string本质上是一个类
string和char * 区别:char * 是一个指针。string是一个类,类内部封装了char*,管理这个字符串,是一个char型的容器。
特点:
string 类内部封装了很多成员方法
例如:查找find,拷贝copy,删除delete 替换replace,插入insert
string管理char
所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责

3.1.1 string构造函数

在这里插入图片描述

3.1.2 string赋值操作

string的赋值方式很多, operator= 这种方式是比较实用的.
在这里插入图片描述

3.1.3 string字符串拼接

在这里插入图片描述

3.1.4 string查找和替换

find查找是从左往后,rfind从右往左
find找到字符串后返回查找的第一个字符位置,找不到返回-1
replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串
在这里插入图片描述

3.1.5 string字符串比较

比较方式:字符串比较是按字符的ASCII码进行对比
= 返回 0

返回 1
< 返回 -1
字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大
在这里插入图片描述

3.1.6 string字符存取

在这里插入图片描述

3.1.7 string插入和删除

插入和删除的起始下标都是从0开始
在这里插入图片描述

3.1.8 string子串

在这里插入图片描述

3.2 vector容器

功能:vector数据结构和数组非常相似,也称为单端数组
vector与普通数组区别:不同之处在于数组是静态空间,而vector可以动态扩展
动态扩展:并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间。
vector容器的迭代器是支持随机访问的迭代器。
在这里插入图片描述

3.2.1 vector构造函数

在这里插入图片描述

3.2.2 vector赋值操作

给vector容器进行赋值
在这里插入图片描述

3.2.3 vector容量和大小

在这里插入图片描述

3.2.4 vector插入和删除

在这里插入图片描述

3.2.5 vector数据存取

在这里插入图片描述

3.2.6 vector互换容器

实现两个容器内元素进行互换
在这里插入图片描述

swap可以使两个容器互换,可以达到实用的收缩内存效果。
vector(v).swap(v); //匿名对象

3.2.7 vector预留空间

减少vector在动态扩展容量时的扩展次数,如果数据量较大,可以一开始利用reserve预留空间。
在这里插入图片描述

3.3 deque容器

功能:双端数组,可以对头端进行插入删除操作;deque容器的迭代器也是支持随机访问的。
deque与vector区别:
vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度回比vector快
vector访问元素时的速度会比deque快,这和两者内部实现有关
在这里插入图片描述

deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
在这里插入图片描述

3.3.1 deque构造函数

在这里插入图片描述

3.3.2 deque赋值操作

在这里插入图片描述

3.3.3 deque大小操作

在这里插入图片描述

3.3.4 deque 插入和删除

在这里插入图片描述

3.3.5 deque 数据存取

在这里插入图片描述

3.3.6 deque 排序

利用算法实现对deque容器进行排序(包含头文件 algorithm即可)
在这里插入图片描述

3.4 stack容器(栈)

在这里插入图片描述

3.5queue 容器(队列)

在这里插入图片描述

3.6list容器(链表)

3.6.1 list构造函数

在这里插入图片描述

3.6.2 list 赋值和交换

在这里插入图片描述

3.6.3 list 大小操作

在这里插入图片描述

3.6.4 list 插入和删除

在这里插入图片描述

3.6.5 list 数据存取

在这里插入图片描述

3.6.6 list 反转和排序

在这里插入图片描述

3.7 set/ multiset 容器

所有元素都会在插入时自动被排序,set容器默认排序规则为从小到大,利用仿函数,可以改变排序规则。
本质:set/multiset属于关联式容器,底层结构是用二叉树实现。
set和multiset区别:set不允许容器中有重复的元素;multiset允许容器中有重复的元素 。set插入数据的同时会返回插入结果,表示插入是否成功;multiset不会检测数据,因此可以插入重复数据。

3.7.1 set构造和赋值

在这里插入图片描述

3.7.2 set大小和交换

在这里插入图片描述

3.7.3 set插入和删除

在这里插入图片描述

3.7.4 set查找和统计

在这里插入图片描述

3.7.5 pair对组创建

成对出现的数据,利用对组可以返回两个数据
在这里插入图片描述

3.8 map/ multimap容器

简介:map中所有元素都是pair;pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值);所有元素都会根据元素的键值自动排序。
本质:map/multimap属于关联式容器,底层结构是用二叉树实现。
优点:可以根据key值快速找到value值。
map和multimap区别:map不允许容器中有重复key值元素;multimap允许容器中有重复key值元素。

3.8.1 map构造和赋值

在这里插入图片描述

3.8.2 map大小和交换

在这里插入图片描述

3.8.3 map插入和删除

在这里插入图片描述

3.8.4 map查找和统计

在这里插入图片描述

4 STL- 函数对象

4.1 函数对象

函数对象概念:
重载函数调用操作符的类,其对象常称为函数对象
函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:函数对象(仿函数)是一个类,不是一个函数
函数对象使用特点:
函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可以作为参数传递

4.2 谓词

返回bool类型的仿函数称为谓词
如果operator()接受一个参数,那么叫做一元谓词
如果operator()接受两个参数,那么叫做二元谓词

4.3 内建函数对象

STL内建了一些函数对象

4.3.1 算术仿函数

在这里插入图片描述

4.3.2 关系仿函数

在这里插入图片描述

4.3.3 逻辑仿函数

在这里插入图片描述

5. STL- 常用算法

算法主要是由头文件 组成。
是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等。
体积很小,只包括几个在序列上面进行简单数学运算的模板函数。
定义了一些模板类,用以声明函数对象。

5.1常用遍历算法

在这里插入图片描述

5.1.1 for_each

实现遍历容器
在这里插入图片描述

5.1.2 transform

搬运容器到另一个容器中;搬运的目标容器必须要提前开辟空间,否则无法正常搬运。

//例如
vector<int>vTarget; //目标容器
vTarget.resize(v.size()); // 目标容器需要提前开辟空间
transform(v.begin(), v.end(), vTarget.begin(), TransForm());

在这里插入图片描述

5.2 常用查找算法

在这里插入图片描述

5.2.1 find

查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()。
//例如
//查找容器中是否有 5 这个元素
vector::iterator it = find(v.begin(), v.end(), 5);
在这里插入图片描述

5.2.2 find_if

按条件查找元素, 返回值是迭代器
在这里插入图片描述

5.2.3 adjacent_find

查找 相邻 重复 元素。返回值是迭代器。
在这里插入图片描述

5.2.4 binary_search

查找指定元素是否存在(二分查找), 返回值是bool类型数据。
二分查找法查找效率很高,值得注意的是查找的容器中元素必须的有序序列。
//例如
在这里插入图片描述

//二分查找
bool ret = binary_search(v.begin(), v.end(),2);
5.2.5 count

统计元素个数,返回整型;统计自定义数据类型时候,需要配合重载 operator==。
在这里插入图片描述

5.2.6 count_if

按条件统计元素个数,返回整型。
在这里插入图片描述

5.3 常用排序算法

在这里插入图片描述

5.3.1 sort

对容器内元素进行排序
在这里插入图片描述

5.3.2 random_shuffle

洗牌 指定范围内的元素随机调整次序。使用时记得加随机数种子。
在这里插入图片描述

5.3.3 merge

两个容器元素合并,并存储到另一容器中,merge合并的两个容器必须的有序序列。
在这里插入图片描述

5.3.4 reverse

将容器内元素进行反转
在这里插入图片描述

5.4 常用拷贝和替换算法

在这里插入图片描述

5.4.1 copy

容器内指定范围的元素拷贝到另一容器中,目标容器记得提前开辟空间。
在这里插入图片描述

5.4.2 replace

将容器内指定范围的旧元素修改为新元素
在这里插入图片描述

5.4.3 replace_if

将区间内满足条件的元素,替换成指定元素;注意交换的容器要同种类型。
在这里插入图片描述

5.4.4 swap

互换两个容器的元素
在这里插入图片描述

5.5 常用算术生成算法

算术生成算法属于小型算法,使用时包含的头文件为 #include
在这里插入图片描述

5.5.1 accumulate

计算区间内 容器元素累计总和, accumulate使用时头文件注意是 numeric。
在这里插入图片描述

5.5.2 fill

向容器中填充指定的元素
在这里插入图片描述

5.6 常用集合算法

在这里插入图片描述

5.6.1 set_intersection

求两个容器的交集,求交集的两个集合必须的有序序列,目标容器开辟空间需要从两个容器中取小值,set_intersection返回值既是交集中最后一个元素的位置。
在这里插入图片描述

vector<int> vTarget;//取两个里面较小的值给目标容器开辟空间
vTarget.resize(min(v1.size(), v2.size())); //返回目标容器的最后一个元素的迭代器地址
vector<int>::iterator itEnd =
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
//set_intersection返回值既是交集中最后一个元素的位置,所以for_each第二个元素用itEnd。
5.6.2 set_union

求两个集合的并集,求并集的两个集合必须的有序序列,目标容器开辟空间需要两个容器相加,set_union返回值既是并集中最后一个元素的位置。
在这里插入图片描述

5.6.3 set_difference

求两个集合的差集,求差集的两个集合必须的有序序列,目标容器开辟空间需要从两个容器取较大值,set_difference返回值既是差集中最后一个元素的位置。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值