C++基础语言学习

原材料

  1. 郑莉cpp
  2. C++Perimer
  3. 王道C++学习时课件及笔记
  4. 数据结构(王道)
  5. 6.15-6.28-done

郑莉cpp再读

第一章

  1. 计算机运行二进制代码
  2. cpp -> 预编译 -> 汇编 -> 连接 -> exe
  3. 编译器真滴是个很吊的东西
  4. 浮点数的存储,前一半是有效值,后一半是10的几次方

第二章

  1. 变量的存储类型:
auto存储类型:堆栈分配,暂时性存储,其存储空间可以被若干变量多次使用;
register存储类型:寄存器
extern存储类型:所有函数和程序段都可用
static存储类型:内存中以固定地址存放的,整个程序运行期有效。
  1. 隐式转换:两个操作数先隐式转换为等级高操作数的级别,都小于int就转换都隐士转换为int进行。
  2. 四种转换类别:
const_cast
dynamic_cast
reinterpret_cast
static_cast

第四章 类与对象

  1. 类的组合、 初始化列表(深入理解)
  2. 结构体(默认权限public、默认继承权限)
  3. 联合体:全部数据成员共享一组内存单元,无名联合体通常用作结构体或类的内嵌成员。
union 联合体名称 
{
公有成员
protected:
private:
}
union Mark {
	char grade;
	bool pass;
	int percent;
}
  1. 位域
  2. explicit声明

第五章数据的共享与保护

  1. static 变量仅第一次定义时初始化,后续定义语句无效,demo含类中的一个static 变量(类中仅声明未创建、需额外全局定义变量值)、模板中定义static变量(定义一个类的时候创建)。
  2. 友元函数、友元类的传递关系、继承关系。
  3. 常对象不能调用普通的成员函数。
  4. 常成员函数:const关键字可用于重载;调用常成员函数对象自动变为常对象
  5. 常数据成员:只能通过初始化列表初始化;静态常数据成员在类外说明和初始化(静态变量加常:有点变成全局对象的意思);
  6. 常引用
  7. 外部变量、外部函数。匿名保护:1-static全局关键字(old);2-namespace{}
  8. const成员函数、对象与mutable;单个文件的代码段、数据段(初始化未初始化):静态生存期的、
  9. 编译链接

第六章

  1. 静态生存期的变量在程序开始运行前就已经被分配了内存空间,具有动态生存期的变量,是在程序运行时遇到变量声明语句时被分配内存空间的。
  2. 指向函数的指针:typedef int (*DoubleIntFunction) (double); 声明:void (*functionTest) (float)
  3. this 指针,构造函数
  4. 指向类的非静态成员的指针(变量和函数):int (Point:: *funcptr)() const = &Point::getX 调用:cout << (a. *funcPtr)() << endl; 这里加了类名取函数地址:只是记录了偏移。用的时候需要对象去调用;如果没加类名直接取函数地址,第一个参数需要设置为具体对象的地址才行。
  5. 动态内存分配,new 和delete的三部曲。
  6. new T 和 new T() 后者会默认初始化未0 数据: new int[10] (): 会把数据元素初始化为0
  7. 多维数组的new: float (*cp)[25][10]; cp = new float[10][25][10];
  8. static_cast 与interpret_cast 的转换,static编译器会做类型检查(void转任何类型也不会检查) interpret全部可以转
  9. const_cast: 将常指针和常引用转换为正常指针和引用,不能作用于常对象

第七章继承与派生

  1. 派生类的定义:
class Derived: public Base1, private Base2 
{
public:
	Derived();
	~Derived();
}
  1. 派生新类的过程:吸收基类成员(全盘接收)、改造基类成员(仅虚函数、同名隐藏)、添加新的成员
  2. 公有继承:基类的公有成员和保护成员的访问属性在派生类中不变。而基类的私有成员不可直接访问。
  3. 私有继承:基类的公有成员和保护成员都以私有成员身份出现在派生类中(主要是公有函数也变成私有的了)。而基类的私有成员不可直接访问。
  4. 保护继承:基类的公有成员和保护成员都以保护成员身份出现在派生类中。而基类的私有成员不可直接访问。
  5. 类型兼容规则:派生类的对象可以隐含转换为基类对象;派生类的对象可以初始化基类的引用;派生类的指针可以隐含转换为基类的指针。
  6. 派生类的构造和析构函数、复制构造函数(也有初始化列表)
  7. 派生类成员的标识与访问(同名隐藏)
  8. 虚基类:class 派生类名:virtual 继承方式 基类名(276页给第一辈的继承类加的,不是第二辈)
  9. 派生类对象的内存布局(单继承、多继承):多继承->指针转换发生了指针偏移;在多继承情况下。执行基类到派生类指针的显示转换时,有时需要将指针所存储的地址值进行调整后才能得到新指针的值(300页左右)
  10. void指针多继承的情况下,指针转化可能会问题。void直接转换时没有指针偏移的操作

第八章 多态

  1. 多态的类型:重载多态、强制多态、包含多态、参数多态 --> 编译时多态和运行时多态
  2. 运算符重载:成员函数重载、非成员函数重载 前置++没有int,后置有int。
    demo:返回类型 operator 运算符 (形参表)
  3. 虚函数:基类virtual声明、派生类符合复制兼容规则重写、通过指针或者引用调用。派生时基类与派生类构造函数中关于虚函数,构造与析构时时咋实现的。
  4. 虚函数多级继承中默认形参值只第一次声明的有效,后续无效
  5. 虚析构函数、纯虚函数与抽象类(不能实例化)。demo: virtual 函数名称 函数名(参数表)=0。抽象类不能实例化,但是可以使用其指针和引用
  6. 运行时类型识别:dynamic_cast执行基类向派生类的转换
//背景:与static_cast不同的是,不是无条件的转换,转换前会做检查
如果执行的是指针类型的转换,会得到空指针
如果执行的是引用类型的转换,会抛出异常
转换前类型必须是指向多态类型的指针,或多态类型的引用,
因为C++只为多态类型在运行时保存用于类型识别的信息,--> 非多态类型不易被公有继承
  1. 用typeid获取运行时类型信息
demo:
typeid(表达式)  --> typeid5+3typeid(类型说明符) --> typeid(int)
typeid 得到一个type_info类型的常引用,在typeinfo头文件中。
虽然typeid 可以作用于任何类型的表达式,但只有它作用于多态类型的表达式时,
进行的才是运行时类型识别,否则只是简单的静态类型信息获取。(虚表的-1位置)
  1. 虚函数的实现原理
需求:
	基类定义虚函数的组成,派生类重写,
	基类对象通过派生类指针或者引用调同名函数达到不同的效果
初步想法:
	基类和派生类的所有对象的内存中都包含这个函数的入口地址,
	这个函数的入口地址指向真正的这个函数(类的域名加函数名)
	派生类改写时创建派生类对象的内存的这个地址也发生变化
问题:
	基类和派生类的每个对象都含有这个函数的地址,如果有多个虚函数那会有很多地址,浪费。
改进:
	使用虚表,虚表时每个类的所有对象共用一张,每个对象的内存中仅保存一个虚表的地址,
	虚表中包含所有虚函数的入口地址以及对象的typeid
	(所以有虚函数的派生类一定会有虚表,不会用基类的,因为typeid不同,
	未重写的虚函数还是复制基类的地址)

第九章模板和数据结构

  1. 参数多态:模板是C++支持参数化程序设计的工具,通过它可以实现参数化多态。
    所谓参数化多态,就是将程序处理的对象的类型参数化,使得一段程序可以用于处理多种不同类型的对象
  2. 函数模板:class 或者typename,当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数,这一过程称为函数模板的实例化。
  3. 类模板
  4. array、list、deque(有容量限制、循环队列,front+rear尾后+固定堆区数组)、stack(有容量限制,定义时指定大小 top + 固定堆区数组)的实现
  5. 函数的显示实例化、类模板的特化,类模板的偏特化
C++允许在一部分模板参数固定而对另一部分模板参数可变的情况下规定类模板的特殊实现,
这种行为叫做模板的偏特化,偏特化只是针对类模板
偏特化与特化的不同之处:特化将所有的模板参数都固定了下来,因为对类模板、函数模板特化的结果不再是模板。而是具有普通的类、普通的函数的性质。
但是偏特化由于保留了一部分未定的参数,使得特化的结果仍然是模板,
偏特化非常灵活。除以上外,还允许将一个模板参数所能表示的类型范围缩小,如T 与T*

函数模板的重载
C++不允许将函数模板偏特化。但是可以用模板的重载如T 与 T*

第十一章 输入输出流

第十二章 异常处理

  1. 异常接口声明:
    void func () throw(A,B,C,D) -> 表明函数只能够抛类型abcd及其子类型的 异常

王道C++

需要看primer和stl剖析、深入对象模型、操作系统

  1. 看了一遍,还是得看书去看源码

C++ primer

  1. 暂时先看了前12章,会用为主

数据结构(王道)

栈和队列

  1. 中缀后缀表达式
  2. 双栈实现一个队列
  3. 双队列实现一个栈

树与二叉树

  1. 二叉树的前中后序遍历的非递归写法(栈)
  2. 二叉树的层次遍历(队列)
  3. 由遍历序列构建一颗二叉树
  4. 线索二叉树的构建(pre)
  5. 二叉树从下而上,从右到左的遍历(增加一个栈、出队时入栈)
  6. 查找二叉树中值为x的节点,打印其所有祖先(非递归后序、找p、q的最近公共祖先节点)
  7. 二叉排序树的删除:
普通排序树的删除都有点复杂
叶节点:直接删除
无右子树:用左子女补
无左子树:用右子女补
左右子树都存在:用右子树的中序遍历的第一个结点补,该结点递归删除。
  1. 平衡二叉树(左右子树高度差不超过1)(LL:右单旋转、LR:先左后右双旋)
  2. 哈夫曼树的构建

第五章 图

  1. 图的邻接矩阵存储(二维数组)
  2. 图的邻接表法(链表数组)
  3. 图的广度优先遍历(层次遍历、图中可能会有重复要做标记(双向边必有)、图可能不联通,要把所有顶点都遍历一遍)
  4. 图的深度优先遍历(递归、去重、不连通->all、)
  5. 图的深度优先遍历的非递归写法(用栈)
  6. 最小生成树(Prim算法和克鲁斯卡尔算法)
  7. 单源最短路径迪杰斯特拉算法(单源到所有顶点:O(|V|2))
  8. 各顶点之间路径最短佛罗达算法(O(V3))

第六章 查找

  1. B树:
M阶B树:
每个节点的关键字个数:「m/2] -1 <= n <= m-1;
每个节点至多m棵树:n+1颗
每个关键字都代表了一个真实的元素
每个结点除了包含指向下一级的指针外还保存了该元素在磁盘中的位置(冗余了一倍)
  1. B+树
关键字个数与分支树的个数一致
关键字的含义时下一级的最大key,包含key和指向下一级的指针,无其他冗余信息(非页节点仅索引)
所有真实的元素的key都存放在了叶节点,页节点还包含了真实的元素信息(簇集存储)
页节点用链表串联起来了,可以顺序遍历查找
  1. 数据库为啥用B+树做索引而不是用B树做索引
背景:
	mysql的在MyISAM储存引擎中,数据和索引文件试试分开储存的。但是都在磁盘里(我之前以为索引可以整个放在内存里放的下,想多了),
	Myisam 也是B+树结构,但是MyISAM索引的叶子节点的数据保存的是行数据的地址。
	因此,MyISAM中索引检索的算法首先在索引树中找到行数据的地址,然后根据地址找到对应的行数据。实际真实元素的存储非簇集。
	在InnoDB中,数据和索引文件是合起来储存的。
	在InnoDB虽然底层也是B+树实现的方式,当时与MyISAM却有明显的区别,在InnoDB实现的索引结构中,索引文件和数据文件是一起的,
	InnoDB中索引文件中的key就是数据表中的主键索引,因此InnoDB的索引文件也是主索引文件。
	在InnoDB中的叶子节点中把保存和完整的数据,这就是聚集索引。因为InnoDB是按照主键聚集的,
	两个索引引擎,前者不需要主键,存储非簇集索引。在插入时可在任意位置,删除也是。批量查询效果不高,后者簇集索引。批量查询效果好。但是插入和删除需要移动元素或者链表指针修改,需要很多额外操作,效果不好,查多写少OK。或者用软删除比较好。
查询过程:
	在磁盘取出索引文件。多个级别,一个级别一个级别的读,多一个级别多一次IO
	B树,拿到索引再去磁盘找源数据。单个文件还好,批量性能不好
	B+树,找到包含叶子节点的盘块,直接在磁盘取出该盘块,拿到批量数据
	内存计算很快,瓶颈在磁盘IO
原因:
	B+树索引小一半以上,每个索引盘快可以有更多的索引,索引的高度降低。减少磁盘IO次数
	B+树方便对数据(页节点顺序遍历),磁盘叶节点的主键簇集索引,在批量取一批连续的数据,取一定范围内的数据,在读磁盘方面都很好。
	可以看出MyISAM的索引文件仅仅保存数据记录的地址。
参考:
	https://blog.csdn.net/weixin_36043375/article/details/113349291
	https://www.cnblogs.com/tiancai/p/9024351.html
  1. 散列函数的构造方法:直接定址,除留取余(最常用)、平方取中
  2. 处理冲突的方法:
开放定址法:
	线性探测法:
	平方探测法:
	再散列法:
	伪随机序列法
拉链法(最常用)
  1. 字符串匹配算法:
KMP:O(n+m)
next数组求解(仅与子串有关):出现重复可以直接跳过多少个不用再暴力验证的字符
再次匹配过程。子串的哪个字符不匹配了,在next[i]中取出k,用字符串的第k个字符和源串对上继续匹配
next数组手动求法。01,看前面的子串是否对称

第七章 排序

  1. 插入排序:直接插入、希尔排序 --> 稳定
  2. 交换排序:冒泡排序(稳定)、快排(不稳定、先序分治、非递归的实现)
  3. 数组中数字是乱的,把奇数排到偶数前面。
  4. 苏格兰国旗问题
  5. 选择排序:简单选择排序(不稳定)、堆排序(不稳定)
  6. 堆排:单元操作:向上调整、向下调整,建立堆(从i/2-1个父节点开始,直到根节点,每个节点向下调整,O(n),插入(向上调整)、删除(向下调整)输出结果:pop、向下调整)
  7. 归并排序(稳定、后序)
  8. 基数排序(稳定、桶、分配收回多次)
  9. 外部排序(类似希尔排序,先分出几路已经排序好的数组,在归并排序,不过路比较多的时候,这里用败者树,败者树本质上是一个大根堆或者小根堆nlogm 而不是nm)
  10. (1)选择-置换排序:生成初始归并段、:工作区(buffer)、输入文件、输出文件。
  11. (2)最佳归并树:多路归并、哈夫曼树(归并多少次)
  12. (3)归并用败者树
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值