- 博客(35)
- 收藏
- 关注
原创 AVL树的实现
这里a / b / c是三颗高度为h的子树,是一种抽象的概括表示,代表了所有右单旋的场景,由于情况是在非常多,这里我们不一一列举了。:因为10 < b⼦树的值 < 15,将b变成10的右⼦树,10变成15的左⼦树,15变成这棵树新的根,符合搜索树的规则,控制了平衡,同时这棵的⾼度恢复到了插⼊之前的h + 2,符合旋转原则。:因为 5 < b子树的值 < 10,将b变成10的左子树,10变成5的右子树,5变成这颗树新的根,符合搜索树的规则,控制了平衡,同时这棵树的高度恢复到了插入之前的h+2,符合旋转原则。
2026-01-08 15:50:48
346
原创 二叉搜索树简述
若左子树不为空,则左子树上所有结点都小于根节点的值若右子树不为空,则右子树上所有结点都大于根节点的值它的左右子树也分别为二叉搜索树二叉搜索树对插入的值没有要求,即可以相等。等容器的底层使用的就是二叉搜索树。T _key;
2026-01-04 17:38:49
647
原创 多态理论与实践
多态是一个继承关系下的类对象,去调用同一函数产生不同的行为。Student继承了Person。Person对象买全价票,Student对象优惠买票。实现多态还有两个必须的重要条件必须是基类的指针或引用:因为只有基类的指针或引⽤才能既指向基类对象⼜指向派⽣类对象;派⽣类必须对基类的虚函数完成重写 / 覆盖:重写或者覆盖了,基类和派⽣类之间才能有不同的函数,多态的不同形态效果才能达到。
2025-12-30 21:34:29
764
原创 继承的理论与实践应用
继承的概念:继承机制是面向对象程序设计是代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称子类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们看到的大都是函数层次的复用,而继承是类设计层次的复用。下面我们看到没有继承之前我们设计了两个类Student和TeacherStudent和Teacher都有姓名 / 地址 /电话 / 年龄等成员变量和identity成员函数涉及到两个类里面即使冗余的。
2025-12-27 13:50:05
611
原创 C++ 的容器适配器——从stack/queue看
适配器的作用是“将一个类的接口转换为客户希望的另一个接口”。stack:只允许在一端插入/删除;queue:允许在一端入、一端出(FIFO)。适配器并不自己管理内存,而是复用底层容器(dequevectorlist等)。理解容器适配器的核心在于“接口的封装”和“底层容器的选择”。实现时应注意模板默认参数写法、成员函数的 const/ noexcept 语义与空容器的边界条件。通过上述改进可以让自实现的stack更安全、更 STL 风格、更易于扩展。
2025-12-17 16:05:23
412
原创 list的实现和使用
push_backpush_front: O(1)insert(在已知位置): O(1)erase(给定迭代器): O(1)find(基于值): O(n)splice:O(1)(只是改变指针,不拷贝)sort()list::sort): O(n log n)(归并排序): O(n)注意:虽然对单个已知位置的插入/删除为 O(1),但查找位置仍然可能需要 O(n)。
2025-12-12 11:41:18
815
原创 vector的使用和模拟实现
有了前面的经验,这里对于vector在vector中我们同样可以使用reserve来为数组预留空间。但vector比string多出了一个resize的操作。的插入元素主要依赖push_back和insert两种操作,但值得注意的是,insert操作只支持迭代器操作,同理,erase操作同样也只支持迭代器操作。我们可以使用vector模拟实现出一个stringstring中存在\0,但vector中不存在。vector。
2025-12-09 15:50:15
245
原创 初步了解STL和string
STL- 标准模板库) :是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。
2025-11-30 23:41:23
862
1
原创 深度解析类和对象(2)
紧接上文深度解析类和对象(1)默认成员函数就是用户没有显示实现,编译器会自动生成的成员函数称为默认成员函数。在一个类中,当我们什么都不写的情况下编译器会默认生成下面介绍的6个成员函数,其中需要注意的是前4个,最后两个取地址重载相对来说不那么重要,只需要稍微了解一下即可。其次就是,C++11标准中还新增了两个默认成员函数:移动构造和移动赋值,这个在稍后一些会有相关讲解。其中,默认成员函数是很重要也很复杂的,我们主要需要从下面两个方面进行学习:构造函数是特殊的成员函数,需要注意的是:构造函数虽然名称叫构造,
2025-11-16 23:09:25
742
原创 深度解析类和对象(1)
class Datapublic://小tips:类内定义的函数默认都是inline(内联)的_day = day;private://这里只是声明,没有开空间int _year;int _month;int _day;class为定义类的关键字,{}中为类的主体,类的名字可以由自己随意定义(注意类定义结束时后面分号不能省略)。类体中的内容称为类的成员:类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。
2025-11-07 13:10:56
763
原创 C++中的内存管理
在了解C++中内存管理之前,我们需要先大致了解一下程序中内存区域的划分,一般来说,我们将其分为六个区域,分别为:内核空间、栈、内存映射段、堆、数据段和代码段。,那么我们删除的就只是首元素的地址而不包含数组中开辟的其他空间,这样就十分容易出错,造成内存泄漏导致程序崩溃。这时,但我们调用C语言中的内存管理函数时,它只会开辟出一份空间而不进行初始化,但当我们使用。在C语言中,我们已经有了集中动态的内存管理方式,没有印象的读者可以阅读一下笔者之前的。值得注意的是,在删除数组空间的时候,我们使用的是。
2025-11-04 15:16:54
680
原创 关于C++的面向对象
C++是一种支持面向对象编程(OOP)的高效语言,其核心概念包括封装、继承和多态。面向对象的设计模式能提升代码的可维护性、复用性和扩展性,使程序结构更加清晰。引用不是新定义一个变量, 而是给已存在变量取了一个别名, 编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。比如:水壶传中李逵叫“铁牛”, 江湖上人称“黑旋风";林冲,外号豹子头;类型& 引用别名 = 引用对象int main()int a = 0;//引用:b和c是a的别名int& b = a;int& c = a;
2025-10-19 15:02:51
782
原创 函数栈帧的创建和销毁
经历了上述描述的过程,我们就完整的走完了函数栈帧的创建销毁的过程。每一个函数调用时,都要在栈区开辟一个空间,这个空间就叫做函数栈帧,它是由 ebp 和 esp 两个寄存器共同维护的,且当前正在调用哪个函数,这两个寄存器就维护哪个函数的函数栈帧。在计算机科学中,函数调用是程序执行的基础,但幕后真正支撑这一过程的是一种精妙而严谨的机制——函数栈帧。这里我们再来看一下局部变量在函数栈帧中是如何创建的:在为函数创建的函数栈帧中,从底部开辟一部分空间,并在其中放入局部变量的值,这样,我们就完成了局部变量的创建。
2025-10-02 00:00:12
862
原创 多源最短路(Floyd算法
多源最短路算法用于解决图中任意两节点间最短路径的问题,广泛应用于交通网络、社交关系分析、路由优化等场景。与单源最短路(如Dijkstra)不同,它一次性计算所有节点对的最短距离,适合需要全局路径规划的场景。
2025-09-13 19:28:37
343
原创 单元最短路问题
在图论中,单元最短路(Single-Source Shortest Path)问题是指在带权有向图或无向图G=(V,E)中,从给定源顶点a出发,计算到图中所有其他顶点b∈V的最短路径及其权重的问题。关键定义带权图:图G中的每条边e∈E都被赋予一个实数值w(e),称为边的权重或长度。路径长度:对于从顶点a到b的一条路径p=(a,v₁,v₂,…,vₖ,b),其路径长度L§定义为该路径上所有边权重的总和。最短路径:在所有从a到b的可能路径中,具有最小路径长度的路径称为a到b的最短路径。
2025-09-11 21:47:41
746
原创 dp类相关问题(2):路径类dp
同样的,在看到这样一道题时,读者一定很容易想到用贪心的策略解决这个问题,即走两次,每次走的时候都按照最大路径的逻辑走,但显然,这种情况是错误的。在初始化时,我们需要注意的是,因为我们的填表顺序是从上往下从左往右的,所以我们只需要将 f[0][i] 和 f[i][0] 都赋0,再确保第一次循环时。我们只需要取上面四种情况的最大值,再判断一下 i1 和 i2 的位置,如果在同一位置,加上一个格子即可,如果在不同位置,则需要分别加上两个格子的数值。,这样我们就可以保证两个小人走的次数是一样的。
2025-09-10 22:45:02
865
原创 dp类相关问题(1):区间dp
线性动态规划(Linear Dynamic Programming)是动态规划中最基础且常见的形式,其核心思想是通过状态转移方程将问题分解为若干线性递推的子问题。通常适用于问题具有“线性结构”或“顺序依赖性”,例如最长上升子序列(LIS)、最大子数组和等问题。通过存储子问题的解(即状态表),避免重复计算,实现高效求解。(对动态规划存有疑问的同学可前往动态规划入门:从记忆化搜索到动态规划处查看)因此,本章节笔者将从具体问题处分析着手,带读者一步一步理解dp问题的含义和解法。
2025-09-09 23:22:47
797
原创 各种背包问题简述
背包问题(Knapsack Problem)是计算机科学和运筹学中的一个经典组合优化问题。给定一组物品,每个物品都有其特定的体积(或重量)和价值,在不超过背包总容量的情况下,如何选择物品装入背包,使得背包中物品的总价值最大化。(在学习背包问题之前,笔者建议先阅读笔者写于之前的动态规划入门:从记忆化搜索到动态规划以便更容易理解背包问题)
2025-09-05 22:56:56
1025
原创 动态规划入门:从记忆化搜索到动态规划
在搜索过程中,当搜索树中存在大量重复的节点时,我们可以通过引入一个"备忘录"(通常是一个数组或哈希表)来优化计算。这个备忘录会记录第一次搜索到某个节点时的计算结果。当后续再次遇到相同的节点时,就可以直接从备忘录中获取之前存储的结果,避免了重复计算的开销。例如,在计算斐波那契数列时,fib(5) = fib(4) + fib(3),而fib(4)又需要计算fib(3)+fib(2)。如果不使用记忆化,fib(3)会被重复计算多次。使用记忆化后,每个fib(n)只需计算一次。递推改递归。
2025-09-05 13:26:33
777
原创 6种主流排序
选择排序(Selection Sort)是一种简单直观的排序算法,其核心思想是通过不断选择未排序部分的最小(或最大)元素,将其与未排序部分的第一个元素交换位置,逐步构建有序序列。常见的排序方法各具特色,有的简单易懂,有的高效稳定,有的则适合特定场景。冒泡排序是一种简单的排序算法,通过重复地遍历待排序序列,比较相邻元素并交换它们的位置,将较大的元素逐渐“冒泡”到序列的末尾。其核心思想是通过相邻元素的比较和交换,使得每一轮遍历后最大的元素移动到正确的位置。函数),确保以该节点为根的子树满足堆的性质。
2025-09-03 17:20:35
883
原创 栈和队列OJ题目简述
栈和队列的核心区别在于处理顺序(LIFO vs FIFO),实际应用中需结合具体场景选择数据结构。经典问题如括号匹配、滑动窗口、树的遍历等,均需深刻理解其底层操作逻辑。
2025-08-28 00:44:46
300
原创 栈和队列(动态内存版)
栈和队列是两种基础但强大的数据结构,广泛应用于计算机科学的各个领域。:栈的容量不足时,通常以2倍大小重新分配内存,确保插入操作的平均时间复杂度为O(1)。栈是一种后进先出(LIFO)的数据结构,支持动态增长。链式结构避免了固定大小数组的空间浪费和溢出问题,适合元素数量变化较大的场景。入栈和出栈的时间复杂度均为O(1),动态扩容时均摊复杂度仍为O(1)。链式队列的空间复杂度为O(n),每个节点需要额外指针空间。空间复杂度为O(n),n为最大元素数量。入队和出队的时间复杂度均为O(1)。
2025-08-27 17:34:49
945
原创 单链表OJ基础讲解(偷懒版)
(这里与笔者之前所写的内容有所区别,之前主要为开辟一个足够大的数组,适用于竞赛或者非动态内容的管理,这里使用的主要为动态规划,如有问题的读者可移步写于早些时候的。利用快慢指针,使快指针比满指针多走n步,当快指针走到最后结尾时,满指针刚好处于倒数第n-1个节点,此时,实现链表的删除即可。先利用快慢指针找出链表的中间节点,然后将链表的后半段翻转再与前面的链表进行比较就可以轻易判断出是否为回文链表。开辟一个新的空间,将新节点插入到链表的头部,同时将节点的指针域指向原来的头节点,成为新的头节点。
2025-08-26 23:27:41
566
原创 二叉树pro:堆
堆,简单来说,就是有着特殊性质的二叉树,但同时也要满足一些特殊的性质:1.首先堆必须是一个完全二叉树。(完全二叉树的定义如有疑问,可以翻阅笔者写于之前的二叉树简述2.如果存在子树,那么该结点的权值大于等于子树中所有结点的权值,这样的二叉树我们称之为大根堆。(反之,如果该结点的权值小于等于子树中所有结点的权值,称之为小根堆)只要满足以上两个“小要求”,我们就能很容易的创建出属于我们的第一个堆。16/ \14 10/ \ /8 7 9读者可以自行尝试将其改造成一个小根堆。
2025-08-21 11:38:54
501
原创 二叉树简述
首先访问A结点,A结点为根结点,将其输出,接着遍历其左子树B,再重复之前的操作,B结点也是其所在子树的根结点,因此,再输出B,再向下遍历D结点并输出,D结点没有左子树,也没有右子树,所以我们将其返回它的父亲结点B,又因为B访问过根结点和左子树了,再遍历其右子树E并输出,E和D一样,都是孩子结点,再向上返回至B,B的所有遍历顺序也全部访问完了,再向上返回A,A的根结点和左子树也都访问过了,我们就去遍历其右子树C,C是孩子结点,遍历结束。宽度优先遍历,顾名思义,是优先遍历二叉树的“宽度”。
2025-08-20 00:08:33
1103
原创 队列的基本性质和STL
队列是一种特殊的访问受限的线性表,它只允许再一段进行插入操作,在另一端进行删除操作。简单来讲,我们可以将其看作超市结账时排队,我们只可以从队尾加入队伍,从对头出队伍。先进先出。空队:队列中没有元素满队:队列中的元素个数达到队列的最大容量入队:向队列中插入元素出队:删除队列中的元素对头和队尾:队列中的第一个和最后一个元素。
2025-08-19 00:31:39
409
原创 递归初阶学习
简而言之,递归就是函数在函数内自己对自己进行调用。以上,即为一个最简单的递归代码。其必须确保存在终止条件,否则会不断递归下去导致程序崩溃。
2025-07-12 01:00:29
442
原创 字符函数和字符串函数
当我们在对C/C++相关内容进行编写或使用时,难免会经常性的对其中的字符或字符串进行使用或其他修改等操作。这时我们在加上头文件或后即可正常使用一些字符或字符串函数。下面,笔者将介绍一些常用的字符函数和字符串函数并将其模拟实现出来以帮助读者更好的了解和使用这些函数。以下是包含在头文件中一些基本的用于判断的函数。使用它,我们可以高效快捷的判断参数的部分内容。
2025-07-10 10:09:52
796
原创 三子棋小游戏的实现
这时候我们就需要一个函数来判断棋盘是否下满,如果已经下满,则返回1退出棋盘,否则则返回0继续游戏。在此处,我们采取的的是与我们日常生活中最简单的由两条横线一条竖线构成的三子棋棋盘。在游戏开始之前,我们需要构建出一个初始化的棋盘用以游戏的进行。通过以上的方法我们就可以获得一个简易的由C语言完成的三子棋小游戏。在该段代码中,我们首先需要判断的是玩家的落子是否超出棋盘以及是否在已经下过棋的重复落子。我们可以写一个game函数使其在主函数中的写法更加简洁,同时调用速度快,方便使用。的代码块,使用无符号的。
2025-01-14 21:44:43
553
原创 自定义类型 --- 结构体
通过以上操作,我们就完成了一个结构体的声明。其中,struct是结构体的关键字,book为结构体的标签名(可以自定义),name author等为结构体成员。结构体成员禁止初始化。方式一:在结构体后边直接创建结构体变量。方法二:在主函数中创建。在主函数创建时可以为结构体变量赋值补充:匿名结构体类型不能通过主函数中 struct x 的方式创建结构体变量。只能在结构体后面直接创建注意:不能用 这样的声明方式,因为 next 时结构体变量,不能再定义结构体变量。即结构体变量中不能再含有结构体变量。
2024-12-27 14:31:42
1172
原创 C语言指针的基本认识2
1.数组就是数组,是一块连续的空间,是可以存放一个或者多个数组。2.指针变量是一个变量,是可以存放地址的变量。数组和指针变量不是一回事,但是可以通过指针来访问数组。为什么可以用指针访问数组?1.数组在内存中连续存放。2.指针的元素可以很方便的遍历数组,去除数组的内容(指针运算)。
2024-12-21 16:14:49
696
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅