递归
2.2 迭代与递归 - Hello 算法
递归(recursion)是一种算法策略,通过函数调用自身来解决问题。它主要包含两个阶段。
递:程序不断深入地调用自身,通常传入更小或更简化的参数,直到达到“终止条件”。
归:触发“终止条件”后,程序从最深层的递归函数开始逐层返回,汇聚每一层的结果。
而从实现的角度看,递归代码主要包含三个要素。
终止条件:用于决定什么时候由“递”转“归”。
递归调用:对应“递”,函数调用自身,通常输入更小或更简化的参数。
返回结果:对应“归”,将当前递归层级的结果返回至上一层。迭代与递归可以得到相同的结果,但它们代表了两种完全不同的思考和解决问题的范式。
迭代:“自下而上”地解决问题。从最基础的步骤开始,然后不断重复或累加这些步骤,直到任务完成。
递归:“自上而下”地解决问题。将原问题分解为更小的子问题,这些子问题和原问题具有相同的形式。接下来将子问题继续分解为更小的子问题,直到基本情况时停止(基本情况的解是已知的)。
递归函数每次调用自身时,系统都会为新开启的函数分配内存,以存储局部变量、调用地址和其他信息等。这将导致两方面的结果。
函数的 ...
二叉搜索树VS小顶堆
左子树中所有节点的值<父节点的值<右子树中所有节点的值;小顶堆是父节点的值<=左/右子树中所有节点的值;
关键区别总结
性质
二叉搜索树(BST)
小顶堆(Min-Heap)
节点关系
左 < 父 < 右
父 ≤ 左子 且 父 ≤ 右子
左右子节点关系
左子节点 < 右子节点(因左 < 父 < 右)
左子节点和右子节点无明确大小关系
结构目的
快速搜索、插入、删除(O(log n))
快速获取最小值(O(1))
是否完全二叉树
不一定
通常实现为完全二叉树(数组存储)
图
请参考网页,尤其是邻接矩阵和邻接表定义:9.1 图 - Hello 算法
图遍历:BFS: BREADTH队列维护遍历顺序,哈希集防止重复遍历
将遍历起始顶点 startVet 加入队列,并开启循环。
在循环的每轮迭代中,弹出队首顶点并记录访问,然后将该顶点的所有邻接顶点加入到队列尾部。
循环步骤 2. ,直到所有顶点被访问完毕后结束。
为了防止重复遍历顶点,我们需要借助一个哈希集合 visited 来记录哪些节点已被访问。
DFS 算法“根 左 右”“左 根 右”“左 右 根”分别对应前序(Preorder)、中序(Inorder)、后序(Postorder)遍历,记忆:都是左先右后,只是根的位置,依次是前、中、后,因此说的是根的顺序
字符编码
ASCII: A:65,a:97
GB2312:1980年,6763 个汉字(缺点:无法处理部分罕见字和繁体字)
GBK:21886 个汉字,ASCII 字符使用一个字节表示,汉字使用两个字节表示。(缺点:通用性差)
Unicode 字符集:世界通用码(缺点:空间效率不是最优,没考虑码率)
UTF-8:变长编码,国际规范,使用 1 到 4 字节来表示一个字符,根据字符的复杂性而变。ASCII 字符只需 1 字节,拉丁字母和希腊字母需要 2 字节,常用的中文字符需要 3 字节,其他的一些生僻字符需要 4 字节。
Python 和 C++ 中的舍入问题
在 Python 和 C++ 中,**int 强制转换(或构造函数)采用的是“截断取整”(Truncate),即直接丢弃小数部分,保留整数部分,不进行四舍五入**,向0舍入。
Python 中的 int() 强制转换
行为:直接截断小数部分(向零取整)。
示例:12print(int(3.7))# 输出: 3(直接丢弃 0.7)print(int(-2.9))# 输出: -2(直接丢弃 -0.9,不是 -3!)
关键点:
对正数相当于向下取整(floor),但对负数相当于向上取整(ceil),本质是向零靠近。
与 math.trunc() 行为完全一致:12import mathprint(math.trunc(3.5))
对比总结cmath库
方法
Python
C++
向下取整
math.floor(x)
std::floor(x)
向上取整
math.ceil(x)
std::ceil(x)
四舍五入
round(x)
std::round(x)
截断取整
math.trunc(x)或int(x)
std::trunc(x)
Python的rou ...
哈希冲突
哈希冲突(Hash Collision)是指不同的键(key)通过哈希函数计算后得到相同的哈希值(即相同的存储位置)。解决哈希冲突的方法主要有以下几种,每种方法各有优缺点,适用于不同场景:
1. 开放寻址法(Open Addressing)核心思想:如果目标位置已被占用,就按照某种规则(探测序列)寻找下一个空闲位置。常见探测方式:
线性探测(Linear Probing)
冲突时,顺序检查下一个位置(如 h(key)+1, h(key)+2, ...)。
缺点:容易导致“聚集”(Clustering),即连续占用位置,降低查找效率。
平方探测(Quadratic Probing)
冲突时,按平方步长探测(如 h(key)+1², h(key)+2², ...)。
减少聚集问题,但可能无法遍历所有位置(需保证表大小为质数)。
双重哈希(Double Hashing)
使用第二个哈希函数计算步长(如 h1(key) + i*h2(key))。
探测序列更分散,冲突概率低,但计算成本略高。
优点:无需额外存储空间(如链表),适合数据量小、装载因子(load factor)低的场景。缺点 ...
红黑树:自平衡的二叉搜索树
红黑树(Red-Black Tree)详解红黑树是一种自平衡的二叉搜索树(BST),它通过特定的规则确保树的高度始终保持在 (O(\log n)),从而保证查找、插入、删除等操作的最坏时间复杂度为 (O(\log n))。它是计算机科学中最重要的数据结构之一,广泛应用于各类高效的数据存储和检索场景(如C++ std::map、Java TreeMap、Linux内核调度器等)。
平衡反转二叉树 ≠ 红黑树. 平衡反转二叉树(如 AVL树)和红黑树(Red-Black Tree)都是自平衡二叉搜索树(BST),但它们采用不同的平衡策略,适用于不同场景。
1. 红黑树的五大性质红黑树通过以下规则维持平衡性:
节点是红色或黑色。
根节点是黑色。
所有叶子节点(NIL节点,空节点)是黑色。
红色节点的子节点必须是黑色(即不能有两个连续的红色节点)。
从任意节点到其所有叶子节点的路径上,黑色节点的数量相同(称为“黑高”一致性)。
📌 为什么这些规则能保证平衡?
规则4和5确保:最长路径(红黑交替)不超过最短路径(全黑)的两倍,避免极端不平衡。
树高被约束为 (O(\log n))。
...
抽样方法
渐进抽样
渐进抽样是一种动态抽样方法,它通过逐步增加样本量,直到达到所需的精度或稳定性。
适用于样本容量难以预先确定的情况,因为它允许根据数据的实际情况动态调整样本量。
A. 有放回的简单随机抽样
B. 无放回的简单随机抽样:
C. 分层抽样: