- 博客(63)
- 收藏
- 关注
原创 数据结构----希尔排序
直接插入:简单、稳定、O(n 2)折半插入:减少比较次数、仍 O(n 2 )、稳定希尔排序:分组增量优化、O(n 1.3)、不稳定。
2026-04-29 21:28:45
347
原创 数据结构----插入排序
算法逻辑简单,易于理解、代码短;适合数据量小、基本接近有序的序列;直接插入、折半插入:稳定;希尔排序:不稳定;都是就地排序,额外空间仅常数级;数据越有序,插入排序越快。
2026-04-28 21:23:59
168
原创 数据结构--散列函数的构造方法
直接定址法:无冲突,仅限连续关键字;数字分析法:靠数位筛选,适合已知固定样本;平方取中法:平方乱序,中间取值,分散性好;折叠法:分段叠加,适合长关键字;除留余数法:万能通用,考试核心、首选方法。
2026-04-28 20:30:44
254
原创 Java List 接口知识点详解
继承关系List是 Java 集合框架(Collection Framework)中的一个有序队列接口,直接继承自Collection接口。核心特性有序性:元素按插入顺序存储,可通过索引(Index)访问元素。可重复性:允许存储重复元素。动态扩容:底层实现类(如ArrayListLinkedList)支持动态调整容量。特性List 接口特点核心优势有序性、可重复性、索引访问,适用于需要按顺序操作的数据场景。实现类选择ArrayListLinkedList常用操作。
2026-04-28 20:30:25
472
原创 【数据结构】 散列表
优点平均查找、插入、删除时间复杂度 O(1),效率碾压顺序查找、折半查找、树形查找;寻址逻辑简单,无需关键字多次比较;适合海量数据高频增删、快速检索场景。缺点无法支持有序遍历、范围查询,仅适合精准匹配;哈希冲突会退化效率,最坏情况退化为线性查找;存储空间存在冗余,开放定址法利用率受装填因子限制;关键字必须可哈希,部分复杂数据类型映射困难。散列表是一种直接寻址的高效查找结构,区别于传统比较类查找,依靠哈希函数实现关键字到存储地址的直接映射。
2026-04-27 23:43:03
321
原创 【数据结构】 红黑树
红黑树 是一棵自平衡的二叉排序树 BST相比 AVL(严格高度平衡),红黑树是弱平衡;不严格限制左右高度差,只通过结点颜色 + 5 条规则维持大致平衡。核心目的:减少旋转次数,插入删除更快,工业级常用(C++map、Java TreeMap 底层)
2026-04-27 23:11:36
225
原创 【数据结构】平衡二叉树
平衡二叉树,简称 AVL 树,是改良版二叉排序树满足两个硬性条件:具备二叉排序树性质左子树所有结点值 < 根 < 右子树所有结点值具备平衡性质任意结点的左、右子树高度差的绝对值 ≤ 1左右子树,也必须是平衡二叉树公式(死记,不能写反)平衡因左子树高度右子树高度合法范围BF∈{−1, 0, 1}BF=1:左子树更高(左偏)BF=0:左右等高(完全平衡)BF=−1:右子树更高(右偏)∣BF∣≥2:树失衡,必须旋转调整普通二叉排序树 BST有序序列插入会变成斜树,查找复杂度退化到 O(n)
2026-04-27 22:49:40
297
原创 【数据结构】图----图的应用(拓扑排序)
有向无环图 DAG入度数组+ 删边减入度判定有环:输出顶点个数 <n时间复杂度:O(n+e)序列不唯一:多个入度为 0 的点,选择顺序任意。
2026-04-25 23:04:09
104
原创 图---图的应用(最小生成树)
最小生成树 (MST):含图全部 n个顶点、仅 n−1条边、权值和最小、无环连通子图。维护数组 lowcost[]:记录「生成树集合」到每个顶点的最短边权。加入后,更新剩余点的 lowcost循环 n−1次,得到 MST。不连通:选这条边,合并集合、累加权选够 n−1条边停止。每次选:lowcost 最小且未加入树的顶点入树。Kruskal:边贪心,稀疏图,配合并查集判环。时间:O(eloge)(主要消耗在排序)Prim:点贪心,稠密图、邻接矩阵。适用:连通无向带权图。时间:O(n 2 )
2026-04-25 21:18:03
60
原创 图——图的存储及基本操作(邻接矩阵法)
用n 阶方阵存储 n 个顶点的图行、列都对应顶点,矩阵元素表示两点有没有边、边权多少。顶点度数 = 第 i 行(第 i 列)1 的个数。特点:矩阵对称A[i][j]=A[j][i]对角线:A[i][i]=0(自己不连自己)<i,j>存在:A[i][j]=1。n 个顶点就要 n 的2次个 空间。n 个顶点 → 矩阵大小 n×n。有边:A[i][j]=1。不存在:A[i][j]=0。求入度、出度、度数非常方便。无边:A[i][j]=0。第 i行和 = 出度。删除、插入顶点不方便。无向对称,有向不对称。
2026-04-24 00:47:38
34
原创 图——图的基本概念
有向图:所有入度之和 = 所有出度之和 = 边数。双向互通A-B 与 B-A 是同一条边。无向图:所有顶点度数之和 = 2× 边数。简单回路:除起点终点外,其余顶点不重复。无向图顶点度:依附该顶点的边的条数。强连通分量:有向图极大强连通子图。无向完全图:2n(n−1)条边。有向完全图:n(n−1) 条边。连通分量:无向图极大连通子图。E:边集合(顶点之间关系)回路(环):起点 = 终点。路径:顶点依次相连的序列。起点:弧尾,终点:弧头。出度:从该点出发的边数。连通图:任意两点都连通。
2026-04-23 17:14:02
44
原创 树、森林——树与二叉树的应用(并查集的优化)
不优化的并查集,树会变得又高又瘦查找祖先速度变慢,最坏退化成链表,时间复杂度 O (n)路径压缩 + 按秩合并时间复杂度:阿克曼反函数 α(n)可以理解为常数级 O (1)查找某个结点根结点时把沿途所有结点,直接指向根结点让树变得极度扁平。查找路上路径压,合并高矮不瞎挂,树矮扁平速度快,近乎常数顶呱呱。合并两棵树时矮树的根 挂在 高树的根下面不让树越长越高。单独路径压缩:效率极高,但树高度不稳定。路径压缩:优化查找,扁平化树形结构。按秩合并:优化合并,保持树平衡低矮。单独按秩合并:树平衡,但查找不够快。
2026-04-23 11:59:23
52
原创 树、森林——树与二叉树的应用(并查集的基本实现)
双亲表示法 一维数组无路径压缩:O (logn)近似 O (1)用途:Kruskal 最小生成树、判断连通分量。
2026-04-23 11:01:06
53
原创 树、森林——树与二叉树的应用(并查集的存储结构)
双亲表示法 + 一维数组只用一个 parent[] 数组就能实现,不用链表、不用二叉树。下标: 0 1 2 3 4parent:-1 0 0 2 2。额外开一个 rank[] 数组,记录树高度 / 结点个数。parent[i]:表示下标为 i 的结点双亲结点下标。根结点(集合代表):parent[i] = -1。查找时修改数组内容,让结点直接指向根,树变扁平。普通结点:parent[i] = 父节点编号。根节点标记:parent[i] = -1。父结点指向祖先,最终汇聚到根结点。并查集 = 一维双亲数组。
2026-04-23 00:28:22
28
原创 树、森林——树与二叉树的应用(哈夫曼树编码)
左 0 右 1 根到叶,大权短码小长些,互不前缀无歧义,最短编码哈夫曼。从根出发遇 0 走左,遇 1 走右走到叶子,输出对应字符依次重复即可。从根走到叶子,依次记录 0、1就是该叶子对应字符的哈夫曼编码。(左右可以互换,编码不唯一,但最短总长度唯一)前缀编码:任意一个编码都不是另一个编码的前缀。哈夫曼树没有度为 1 结点,不会出现多余码位。编码不唯一,但最短 WPL 唯一。整体平均码长最短,最优前缀编码。根 → 叶子,顺着路径写二进制。左路 = 0,右路 = 1。n 个叶子,总共n 个编码。
2026-04-23 00:18:53
32
原创 树、森林——树与二叉树的应用(哈夫曼树的构造)
每次选两个权最小结点,合并出新父结点,重复直到只剩一个。把所有带权叶子结点看成一棵只有根的二叉树,构成森林。n 个叶子结点 → 总结点数 = 2n - 1。新建一个父结点,权值 = 两结点权值之和。左右孩子没有严格顺序,所以哈夫曼树不唯一。合并出新结点一定是分支结点,不带原始权。n 个叶子,分支结点 = n-1 个。两棵小树分别作为新父结点左、右孩子。哈夫曼树绝对没有度为 1 的结点。举例(权:1,2,3,4)选 1、2 → 合并 3。选 3、3 → 合并 6。总结点 = 2n-1。不存在度为 1 结点。
2026-04-22 20:48:35
43
原创 树、森林——树与二叉树的应用(哈夫曼树的定义)
哈夫曼树在n 个带权叶子结点构成的所有二叉树中带权路径长度 WPL 最小的二叉树→ 称为哈夫曼树(最优二叉树)带权路径长度 WPL树中所有叶子结点的权值 × 该结点到根的路径长度,全部相加。哈夫曼树就是带权路径长度最短的二叉树,权大离根近,权小离根远。n 个叶子结点 → 总结点数 = 2n - 1。哈夫曼树不唯一,但最小 WPL 唯一。只有叶子结点有权值,分支结点无权值。哈夫曼树没有度为 1 的结点。权值越大的叶子,离根越近。权值越小的叶子,离根越远。
2026-04-22 17:00:36
42
原创 树、森林——树和森林的遍历(森林的遍历)
森林由多棵互不相交的树组成,遍历规则:按树的顺序依次遍历每一棵树。树 ↔ 二叉树 / 森林 ↔ 二叉树 遍历对照表(必背)对应关系:森林先序遍历 = 对应二叉树 先序遍历。对应关系:森林中序遍历 = 对应二叉树 中序遍历。二叉树还原森林,遍历序列完全不变。森林先序遍历 ⇔ 二叉树先序。森林中序遍历 ⇔ 二叉树中序。先序遍历第一棵树的所有子树。中序遍历第一棵树的所有子树。树先根遍历 ⇔ 二叉树先序。树后根遍历 ⇔ 二叉树中序。普通树、森林都没有中序遍历。依次先序遍历剩下所有树。访问第一棵树的根结点。
2026-04-22 16:02:04
57
原创 树、森林——树和森林的遍历(树的遍历)
普通树只有两种遍历方式:先根遍历、后根遍历树没有中序遍历!顺序:根 → 第一棵子树 → 第二棵子树 → …顺序:第一棵子树 → 第二棵子树 → …孩子兄弟转换后,直接套用二叉树遍历算法即可。树先根遍历 = 对应二叉树 先序遍历。树后根遍历 = 对应二叉树 中序遍历。树:A├─ B├─ C└─ D。遍历时间复杂度一律 O(n)先根序列:A B C D。后根序列:B C D A。依次递归遍历每一棵子树。依次递归遍历每一棵子树。普通树不存在中序遍历。
2026-04-22 13:11:18
71
原创 树、森林——树、森林与二叉树的转换(二叉树转换为森林)
拆分右链从根结点开始,沿着右孩子一路拆分每一个右分支断开,独立成一棵二叉树根。每一段二叉树,单独还原成普通树规则逆用:左孩子不变,右兄弟变回兄弟。顺着根的右链不断切断,每一段各自还原成树,拼在一起就是森林。二叉树有根右孩子 → 还原多棵树(森林)二叉树根结点无右孩子 → 原只是一棵树。二叉树根结点有右孩子 → 原是森林。二叉树无根右孩子 → 还原一棵树。根右拆开成多棵,右变兄弟左父子。一棵树 → 二叉树:根无右子树。森林先序遍历 = 二叉树先序。森林 → 二叉树:根有右子树。右孩子:变回原来兄弟结点。
2026-04-22 12:30:15
65
原创 树、森林——树、森林与二叉树的转换(森林转换为二叉树)
第一棵树根不动第二棵树的根 → 作为第一棵树根的右孩子第三棵树的根 → 作为第二棵树根的右孩子依次向右串联。一树转二叉右为空多树相连右相通左挂孩子右挂兄根连根来排成龙。每一棵树,单独转成二叉树规则:左孩子,右兄弟。森林先序遍历 = 对应二叉树 先序遍历。多棵互不相交的树,合在一起就是森林。整理结构,就是森林对应的唯一二叉树。森林转二叉树,根结点一定有右子树。一片森林 → 二叉树:根有右子树。一棵树 → 二叉树:根无右子树。二叉树根右子树:剩下所有森林。二叉树根左子树:第一棵树。顺着根的右链不断拆分。
2026-04-21 23:45:29
80
原创 树、森林——树、森林与二叉树的转换(树转换为二叉树)
删线:只保留父结点和第一个孩子的连线,删掉父与其他孩子连线。旋转:所有连线顺时针旋转 45°,整理成标准二叉树。连线:同一父亲的所有兄弟结点,两两横向连线。普通树转出来的二叉树,根结点一定没有右子树。一棵树 ↔ 一棵二叉树 一一对应,唯一转换。树转二叉树,长子当左孩子,兄弟当右孩子。树中原兄弟 → 变成二叉树右孩子链。树中原父子 → 变成二叉树左孩子链。树 先根遍历 = 二叉树 先序遍历。树 后根遍历 = 二叉树 中序遍历。原树:A├─ B├─ C└─ D。
2026-04-21 23:25:01
62
原创 树、森林——树的存储结构(孩子兄弟表示法)
只保留父→第一个孩子连线,删掉父与其他孩子连线。右指针 rchild:指向本结点右侧相邻兄弟。后一棵树的根,作为前一棵树根的右兄弟依次相连。左指针 lchild:指向本结点第一个孩子。一棵普通树 ↔ 唯一一棵右子树为空的二叉树。孩子兄弟表示法:最通用,树森林二叉树互通。树 先根遍历 = 对应二叉树 先序遍历。树 后根遍历 = 对应二叉树 中序遍历。同一父节点的所有兄弟,两两连线。双亲表示法:查父极快,查孩子慢。孩子表示法:查孩子快,查父慢。整体顺时针旋转 45°。口诀:左孩子,右兄弟。
2026-04-21 22:29:10
61
原创 树、森林——树的存储结构(孩子表示法)
树每个结点可以有多个孩子把每个结点的所有孩子,连成一个单链表整体 = 数组 + 链表 组合结构。数组表头结点data(结点数据)+ firstchild(指向第一个孩子链表头)孩子链表结点childIndex(孩子在数组中的下标)+ next(下一个兄弟)需要遍历整张表所有孩子链表,O (n)直接遍历当前结点孩子链表,效率很高。双亲表示法:查双亲快,查孩子慢。孩子表示法:查孩子快,查双亲慢。A 的孩子链表:B → C。B 的孩子链表:D → E。没有孩子的结点,链表为空。插入删除结点需要修改链表。
2026-04-21 22:20:29
53
原创 树、森林——树的存储结构(双亲表示法)
根结点无双亲:`parent = -1`(或0)利用树的性质:除根结点外,每个结点有且仅有一个双亲。每个数组元素存放:结点数据 + 双亲结点下标。需要遍历整个数组,逐个找双亲是当前结点。一棵树:A(根) → B、C;结点数据:A B C D E。双亲下标:-1 0 0 1 1。2. 根结点 parent = -1。5. 不适合孩子多、频繁找孩子的树。- 其他结点:指向自己父节点位置。3. 适合频繁查询祖先结点的场景。用数组顺序存储树的每个结点。1. 查找双亲结点极其快。
2026-04-21 22:16:22
150
原创 二叉树的遍历和线索二叉树--先序二叉树和后续二叉树
`ltag=0`左孩子,`ltag=1`前驱线索。- `rtag=0`右孩子,`rtag=1`后继线索。4. 构造方式:按对应遍历顺序遍历树,用`pre`记录前驱。2. `rtag=0` → 先找左孩子,没有再找右孩子。1. `rtag=1` → 直接右指针就是后继。5. 三种线索树空间复杂度都是 O(1),不用栈。3. 后序:根最后访问,首尾都要深入子树找。先序线索二叉树,无法找父结点,容易死循环。- 首结点:根结点本身(不用往左找)2. 先序:根最先访问,首结点是根。- 找后继简单,找前驱极难。
2026-04-20 23:26:19
326
原创 二叉树的遍历和线索二叉树--中序线索二叉树的遍历
重复 2、3 步,直到 `p == null` 结束。5. 最后一个结点:整树最右下,右线索指向 null。- `rtag = 1`:right 是后继线索。直接 `p = p.right` 就是后继。- `ltag = 1`:left 是前驱线索。- `rtag = 0`:right 是右孩子。- `ltag = 0`:left 是左孩子。-遍历线索树:不用栈递归,顺着前驱后继线索走。3. 叶子结点左右全是线索,直接顺着走就行。只要 `ltag == 0` 就继续左走。走到不能左走为止,就是最左下结点。
2026-04-20 22:42:58
178
原创 二叉树的遍历和线索二叉树--中序线索二叉树的构造
→ pre 右指针指向当前结点,`pre.rtag=1`2. 定义全局指针 `pre`,永远记录上一个访问过的结点。5. 遍历完当前结点,更新 `pre = 当前结点`- `ltag = 0`:lchild 指向左孩子。- `ltag = 1`:lchild 是前驱线索。- `rtag = 0`:rchild 指向右孩子。- `rtag = 1`:rchild 是后继线索。→ 左指针指向 `pre`,`ltag=1`4. 前驱结点 `pre` 右孩子为空。2. `pre` 是连接前驱后继的关键。
2026-04-20 22:38:35
345
原创 二叉树的遍历和线索二叉树--由遍历序列构造二叉树
普通二叉链表:n 个结点 → 一共 2n 个指针有用指针只有 n-1 个剩余 n+1 个空指针浪费。当前结点左孩子为空 → 左指针连 pre,标记改为线索。前驱结点右孩子为空 → 右指针连当前结点,标记改为线索。ltag = 1:lchild 是前驱线索。rtag = 1:rchild 是后继线索。线索化后:无需栈、无需递归,顺着线索遍历。左指针为空 → 指向中序遍历前驱结点。右指针为空 → 指向中序遍历后继结点。遍历完更新 pre = 当前结点。
2026-04-19 22:34:58
72
1
原创 二叉树的遍历和线索二叉树--由遍历序列构造二叉树
3. 后序拆分:左后序 `D E B`,右后序 `F C`2. n 个结点二叉树,先序、中序、后序序列长度都为 n。3. 先序去掉根,按左右长度分割 → 左先序、右先序。2. 中序分:左 `D B E` ,右 `F C`4. 递归思路:根 → 左子树递归 → 右子树递归。中序左长度 = 先序左长度 = 后序左长度。3.先序 + 后序 → 不能唯一确定二叉树 ❌。4. 左右子树交换,先序↔后序改变,中序不变。3. 后序去掉末尾根,按长度分割左、右后序。中序左:D B E → 左D,右E。
2026-04-19 22:28:18
202
原创 二叉树的遍历和线索二叉树--线索二叉树(代码展示)
中序遍历一遍树,把空左指针指向前驱,空右指针指向后继。永远保存上一个访问过的结点,用来绑定前后线索。线索二叉树不用递归、不用栈,顺着线索走就行。2. 全局前驱结点(记录上一个遍历节点)区分指针到底是孩子还是遍历线索。普通二叉树非递归要用栈。多两个标记 ltag、rtag。ltag=0 左指针指向左孩子。ltag=1 左指针是前驱线索。rtag=0 右指针指向右孩子。rtag=1 右指针是后继线索。4.标记 tag 作用。
2026-04-19 12:18:59
22
原创 二叉树的遍历和线索二叉树--线索二叉树
1. 普通二叉链表:n 个结点,总共有 `2n` 个指针域。- `ltag = 0`:lchild 指向左孩子。- `ltag = 1`:lchild 是前驱线索。- `rtag = 0`:rchild 指向右孩子。- `rtag = 1`:rchild 是后继线索。- 左空指针 → 指向该结点---遍历前驱。- 右空指针 → 指向该结点---遍历后继。- `lchild`:左孩子 / 前驱线索。- `rchild`:右孩子 / 后继线索。2. 有效孩子指针只用了 `n-1` 个。
2026-04-19 12:16:33
194
原创 二叉树的遍历和线索二叉树--二叉树的遍历
1. 已知先序 + 中序 → 唯一确定一棵二叉树。2. 已知后序 + 中序 → 唯一确定一棵二叉树。5. 时间复杂度一律 O(n),每个结点访问一次。利用空指针存放遍历前驱、后继,就变成线索二叉树。3. 已知先序 + 后序 → 不能唯一确定。- lchild:左孩子 / 前驱线索。- 先序、后序线索树找前驱后继比较麻烦。- 剩下n+1 个是空指针,严重浪费。- n 个结点,一共有2n 个指针。从上到下,从左到右,一层一层访问。根节点 → 左子树 → 右子树。左子树 → 根节点 → 右子树。
2026-04-18 21:36:49
282
原创 树与二叉树--二叉树的存储结构
1. n 个结点的二叉链表,空指针域个数 = n + 1。最坏单支树,n 个结点却需要 2ⁿ 空间,极度低效。二叉树一共有两种主流存储方式:顺序存储、链式存储。- 优点:灵活、任意二叉树通用、无空间浪费。- 优点:查找父子关系方便、随机访问快。- 缺点:浪费空间、只适合完全二叉树。- 找孩子方便,找父结点麻烦(需要遍历)- 缺点:无法直接找双亲,只能遍历。- 查找父子结点极快,公式直接算。- 任意二叉树都适用,不浪费空间。- 根结点指针唯一标识整棵二叉树。- 优点:找父结点、找祖先都很快。
2026-04-18 21:20:36
527
原创 树与二叉树--二叉树的定义及其主要特性
4. 若 i > 1,是左孩子则父结点为 i/2;是右孩子则父结点为 (i−1)/2。- 只有度为 0 和度为 2 的结点,没有度为 1 的结点。深度(高度)为 k的二叉树,最多有2^k − 1 个结点。1. 总结点数 n = n₀ + n₁ + n₂。- 每个结点最多两个孩子(0、1 或 2 个)二叉树第 i 层上至多有2^(i−1) 个结点。2. 总边数 = 总度数 = n₁ + 2n₂。- 最多只有一个度为 1 的结点,且只有左孩子。- 高度 k,结点总数 = 2^k − 1。
2026-04-17 22:44:26
396
原创 树与二叉树--树的性质
只有度为 0 和度为 2 的结点,没有度为 1 的结点。深度(高度)为 k的二叉树最多有 2^k − 1 个结点。叶子结点数 n₀ = 度为 2 的结点数 n₂ + 1。2. 度为 m 的树(m 叉树)第 i 层最多结点数。- 最多只有一个度为 1 的结点,且一定只有左孩子。6. 完全二叉树下标:左2i、右2i+1、父i/2。- 依次把后一棵树的根作为前一棵树的右孩子。- 第 i 层最多:m^(i-1)个结点。二叉树第 i 层上最多有 2^(i−1)个结点。2. 二叉树第 i 层最多 2^(i−1)
2026-04-17 22:31:47
388
原创 二叉树遍历方式代码解读(3层序遍历)
层序遍历是指从上到下,从左往右,一层一层进行遍历。接下来我将用队列来实现层序遍历(BFS)就是广度优先搜索 BFS。一层处理完再处理下一层。
2026-04-17 22:31:11
30
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅