- 博客(34)
- 收藏
- 关注
原创 迷你编译器
模块化设计:每个阶段职责明确逐步翻译:从高级语言到低级语言的渐进转换中间表示:使用四元式作为通用中间格式优化思想:在编译时完成尽可能多的工作。
2025-11-29 16:04:56
677
原创 单例和工厂模式【详细剖析】
抽象工厂模式是工厂方法模式的进一步扩展,用于创建产品族(一组相关联的产品)。例如:华为的产品族包含手机、平板、手表,苹果的产品族也包含手机、平板、手表。抽象工厂定义创建多个产品的接口,具体工厂实现该接口,创建对应产品族的所有产品。工厂模式的核心价值是解耦对象的创建与使用,通过封装创建逻辑,让系统更易于扩展和维护。简单场景用简单工厂;单一产品扩展用工厂方法;产品族扩展用抽象工厂。同时,在 C++ 中实现工厂模式时,需注意虚析构函数的定义(避免内存泄漏)和智能指针的使用(如。
2025-11-28 14:50:40
783
原创 C++手撕代码
内存管理(智能指针、动态数组)、设计模式(单例)、数据结构操作(链表、队列)、算法实现(排序、反转)、多线程同步(线程安全队列)。代码需兼顾正确性(边界条件、异常安全)和可读性(命名规范、注释),面试时需边写边解释思路,体现对底层原理的理解。
2025-11-04 13:00:59
480
原创 linux【文件系统】
文件 = 内容 + 属性文件分为打开的文件,和没打开的文件打开的文件是谁打开的?进程 — 本质是研究进程和文件的关系没打开的文件,在哪里放着?磁盘中。没有打开的文件非常多,我们要对文件进行增删查改,就需要先快速找到文件文件被打开,必须先加载到内存,在操作系统中会运行多个进程,一个进程可以打开多个文件,因此,操作系统中会存在许多被打开的文件,就需要管理这些文件,先描述,再组织。在内核中,每一个被打开的文件都必须有自己的文件打开对象,包含文件的许多属性。
2025-11-04 12:55:44
786
原创 linux【信号】
对于进程与信号的关系:进程必须有 识别 并 能够处理信号 的能力, 信号没产生,也要具备处理信号的能力 ,因此信号的处理能力,属于进程内置功能的一部分当进程收到信号时,并不一定立即处理,可能在做其他更重要的事,所以在进程收到信号,处理信号期间,一定会有时间窗口,所以进程要具备保存信号的能力信号是进程之间事件异步通知的一种方式,属于软中断(信号来不来,进程不会去等待,而是做自己的事)
2025-10-27 15:43:51
624
原创 C++设计模式
创建型模式(单例、工厂):解决对象创建问题,结合 C++ 构造函数、静态成员、智能指针。结构型模式(装饰器、适配器):解决类 / 对象组合问题,体现 “组合优于继承” 原则。行为型模式(观察者):解决对象间交互问题,依赖 C++ 多态(虚函数)实现解耦。回答时需结合具体场景说明模式的 “为什么用”“怎么用”,并对比相似模式的区别(如工厂方法 vs 抽象工厂,装饰器 vs 适配器)。
2025-10-23 12:25:46
1131
原创 C++多线程、STL
解答死锁是多线程因竞争资源而相互等待的状态(如线程 A 持有锁 1 等待锁 2,线程 B 持有锁 2 等待锁 1),导致程序永久阻塞。死锁的四个必要条件互斥:资源只能被一个线程持有。持有并等待:线程持有部分资源,同时等待其他资源。不可剥夺:资源不能被强制夺走。循环等待:线程间形成等待环路(A→B→C→A)。避免死锁的核心方法按固定顺序加锁:所有线程按相同顺序获取锁(打破 “循环等待”)。// 错误:顺序混乱导致死锁// 线程1:lock(m1), lock(m2)
2025-10-21 14:21:52
366
1
原创 C++面经
回答:两者均用于定义 “常量”,但本质差异源于#define是预处理指令,const维度#defineconst处理阶段预处理阶段(文本替换,无语法检查)编译阶段(有类型检查,生成符号)类型信息无类型(仅文本替换,如,可被当作 int 或 double 使用)有明确类型(如,类型不匹配会编译报错)作用域从定义处到文件结束(可通过#undef取消),无块作用域(如 if 内定义的#define在 if 外仍有效)遵循 C++ 作用域规则(块作用域、类作用域等,如a在 if 外不可见)
2025-10-21 14:12:02
324
原创 【MySQL】详细介绍(两万字)
但是在一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert操作的数据(因为隔离性的实现是通过加锁完成的,而inser待插入的数据不存在,那么一般加锁无法屏蔽这类问题),一个事务insert数据提交后,另一个事务多次查找时,会查找出新的记录,前后不一致,就如同产生了幻觉,这种现象叫做幻读。隔离性的本质上是在数据层面上隔离,不同隔离级别看到的是不同的数据版本,隔离性决定看到的是哪个版本的数据,所以隔离性本质是用MVCC多版本控制来实现的,事务回滚也是用MVCC多版本控制实现的。
2025-04-21 19:53:53
895
1
原创 【数据结构初阶】--- 归并排序
用栈模拟的过程中,试想一下,要让左右区间有序,所以先压右区间,再压左区间,然后要弹出栈顶元素,也就是左区间,再将这个区间的右区间、左区间压入栈中,以此类推,在过程中是没有机会进行归并操作的。快排的非递归可以用栈模拟递归的过程,每次弹出区间的两个边界,从这个区间固定一个值的位置,再压入这个值的左右两个区间,这样的过程实际上模拟的是递归的前序遍历,先将本层的事做完,然后去遍历左右区间。由于每次都是将区间平分成两个区间,让左区间有序,让右区间有序,再进行归并,类似递归的过程类似二叉树的结构,因此,
2024-06-26 22:15:39
924
原创 【数据结构初阶】--- 快速排序
极端情况下,这个范围里的值刚好是升序的,right先走,一直找小,找不到,来到了left的位置,依然没找到,所以right继续走,走到了left前面的位置,此时right就已经越界,Swap(&a[left],&a[right])时就会非法访问。在当前范围中选取左边界,中间和右边界三个数,比较大小,将中间的值作为key,与左边界的值进行交换,然后再进行固定key的操作。每次固定好一个数的位置后,去左区间固定一个数,右区间固定一个数,以此类推,直到要固定数的范围只剩一个数或范围不存在就停止。
2024-06-25 19:44:04
1082
原创 【数据结构初阶】--- 堆的应用:topk
接下来我来讲解topk是什么把前k个数建成小堆后面N-k个数,依次比较,如果比堆顶数据大,就替换他进堆最后这个小堆的值就是最大的前k个思路:我想要在这些数据中找到前十个最大的数,那我就先向内存中开辟十个数的空间,再读取前十个数(文件中最前面的十个数),同时将这是个数构建成一个小堆,之后从文件中每读取一个数据都与堆顶元素比较,如果大于堆顶元素,就用当前读取到的数覆盖这个堆顶元素,再进行向下调整;如果小于对顶元素那就读下一个数据,一直重复到结束,最终,小堆中的是个元素就是所有数据中最大的十个数。
2024-06-17 19:34:53
970
原创 【数据结构初阶】--- 堆
堆其实就是个完全二叉树堆虽然是个完全二叉树,但它是为了服务数组实现高效排序,因此我们就用数组来实现堆int size;//数组的有效存储个数//数组的容量}Heap;
2024-06-17 19:33:43
1933
原创 【数据结构初阶】--- 栈和队列
说明:top:是指向栈顶的位置,还是栈顶的下一个位置,在初始化讨论capacity:表示栈的容量,因为是用顺序表实现,入栈的时候也需要判断是否现有元素个数是否达到容量arr:就是个指向数组的指针int top;}ST;从队的一头插入元素,另一头弹出元素用链表实现队列,那么就需要用到链表的这个结构体队列想要入栈,是尾插,那么总不能每次插入一次就将链表遍历一遍寻找尾结点,所以,我们需要一个指针tail去记录尾结点。
2024-06-14 22:15:35
1123
1
原创 【数据结构初阶】--- 双链表
初始化的时候我们就要创建一个哨兵位,对这个哨兵位进行初始化,哨兵位的prev和next指针都指向自己,里面的data实际上用不上,可以赋值也可以不管,最后返回哨兵位的地址,函数外面实际早已经创建好一个头指针,用来存放这个哨兵位的地址。申请两个指针,一个指针head指向当前的头结点,一个指针head_next指向头节点的下一个节点(即将成为新的头结点),在进行头删操作会方便些,而且代码的可读性很好。和头插思路一样,申请一个临时指针指向尾结点,方便修改哨兵位、新节点、老的尾结点(插入前的尾结点)的指针指向。
2024-06-14 18:27:29
999
1
原创 【数据结构初阶】 --- 单链表
这一节,我所讲的知识都是基于单链表//结点中存储数据的类型//结点中要存储的数据//结点中指向下一个结点的指针}SLTNode;先看这张图:与开头的那张区别就在于头指针phead,这是一个指针变量,用来存放第一个结点的地址,利用该指针就可以依次访问或操作节点中的数据接下来初始化一个指向结点的头指针:(这里是头指针,不是头结点)
2024-06-11 22:47:25
1923
数据结构中常见的8种排序算法,超详细
2024-06-26
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅