mirror of
https://github.com/krahets/hello-algo.git
synced 2025-07-28 04:42:48 +08:00
build
This commit is contained in:
@ -36,3 +36,35 @@ comments: true
|
||||
**Q**:在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢?
|
||||
|
||||
在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 `ArrayList` 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。
|
||||
|
||||
**Q**:原码转补码的方法是“先取反后加 1”,那么补码转原码应该是逆运算“先减 1 后取反”,而补码转原码也一样可以通过“先取反后加 1”得到,这是为什么呢?
|
||||
|
||||
**A**:这是因为原码和补码的相互转换实际上是计算“补数”的过程。我们先给出补数的定义:假设 $a + b = c$ ,那么我们称 $a$ 是 $b$ 到 $c$ 的补数,反之也称 $b$ 是 $a$ 到 $c$ 的补数。
|
||||
|
||||
给定一个 $n = 4$ 位长度的二进制数 $0010$ ,如果将这个数字看作原码(不考虑符号位),那么它的补码需通过“先取反后加 1”得到:
|
||||
|
||||
$$
|
||||
0010 \rightarrow 1101 \rightarrow 1110
|
||||
$$
|
||||
|
||||
我们会发现,原码和补码的和是 $0010 + 1110 = 10000$ ,也就是说,补码 $1110$ 是原码 $0010$ 到 $10000$ 的“补数”。**这意味着上述“先取反后加 1”实际上是计算到 $10000$ 的补数的过程**。
|
||||
|
||||
那么,补码 $1110$ 到 $10000$ 的“补数”是多少呢?我们依然可以用“先取反后加 1”得到它:
|
||||
|
||||
$$
|
||||
1110 \rightarrow 0001 \rightarrow 0010
|
||||
$$
|
||||
|
||||
换句话说,原码和补码互为对方到 $10000$ 的“补数”,因此“原码转补码”和“补码转原码”可以用相同的操作(先取反后加 1 )实现。
|
||||
|
||||
当然,我们也可以用逆运算来求补码 $1110$ 的原码,即“先减 1 后取反”:
|
||||
|
||||
$$
|
||||
1110 \rightarrow 1101 \rightarrow 0010
|
||||
$$
|
||||
|
||||
总结来看,“先取反后加 1”和“先减 1 后取反”这两种运算都是在计算到 $10000$ 的补数,它们是等价的。
|
||||
|
||||
本质上看,“取反”操作实际上是求到 $1111$ 的补数(因为恒有 `原码 + 反码 = 1111`);而在反码基础上再加 1 得到的补码,就是到 $10000$ 的补数。
|
||||
|
||||
上述 $n = 4$ 为例,其可推广至任意位数的二进制数。
|
||||
|
@ -449,7 +449,13 @@ comments: true
|
||||
|
||||
```kotlin title="build_tree.kt"
|
||||
/* 构建二叉树:分治 */
|
||||
fun dfs(preorder: IntArray, inorderMap: Map<Int?, Int?>, i: Int, l: Int, r: Int): TreeNode? {
|
||||
fun dfs(
|
||||
preorder: IntArray,
|
||||
inorderMap: Map<Int?, Int?>,
|
||||
i: Int,
|
||||
l: Int,
|
||||
r: Int
|
||||
): TreeNode? {
|
||||
// 子树区间为空时终止
|
||||
if (r - l < 0) return null
|
||||
// 初始化根节点
|
||||
@ -467,7 +473,7 @@ comments: true
|
||||
/* 构建二叉树 */
|
||||
fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
|
||||
// 初始化哈希表,存储 inorder 元素到索引的映射
|
||||
val inorderMap: MutableMap<Int?, Int?> = HashMap()
|
||||
val inorderMap = HashMap<Int?, Int?>()
|
||||
for (i in inorder.indices) {
|
||||
inorderMap[inorder[i]] = i
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ comments: true
|
||||
/* 移动一个圆盘 */
|
||||
fun move(src: MutableList<Int>, tar: MutableList<Int>) {
|
||||
// 从 src 顶部拿出一个圆盘
|
||||
val pan: Int = src.removeAt(src.size - 1)
|
||||
val pan = src.removeAt(src.size - 1)
|
||||
// 将圆盘放入 tar 顶部
|
||||
tar.add(pan)
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ $$
|
||||
dp[2] = cost[2]
|
||||
// 状态转移:从较小子问题逐步求解较大子问题
|
||||
for (i in 3..n) {
|
||||
dp[i] = (min(dp[i - 1].toDouble(), dp[i - 2].toDouble()) + cost[i]).toInt()
|
||||
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
|
||||
}
|
||||
return dp[n]
|
||||
}
|
||||
@ -559,7 +559,7 @@ $$
|
||||
var b = cost[2]
|
||||
for (i in 3..n) {
|
||||
val tmp = b
|
||||
b = (min(a.toDouble(), tmp.toDouble()) + cost[i]).toInt()
|
||||
b = min(a, tmp) + cost[i]
|
||||
a = tmp
|
||||
}
|
||||
return b
|
||||
|
@ -349,11 +349,7 @@ $$
|
||||
|
||||
```kotlin title="min_path_sum.kt"
|
||||
/* 最小路径和:暴力搜索 */
|
||||
fun minPathSumDFS(
|
||||
grid: Array<Array<Int>>,
|
||||
i: Int,
|
||||
j: Int
|
||||
): Int {
|
||||
fun minPathSumDFS(grid: Array<IntArray>, i: Int, j: Int): Int {
|
||||
// 若为左上角单元格,则终止搜索
|
||||
if (i == 0 && j == 0) {
|
||||
return grid[0][0]
|
||||
@ -366,7 +362,7 @@ $$
|
||||
val up = minPathSumDFS(grid, i - 1, j)
|
||||
val left = minPathSumDFS(grid, i, j - 1)
|
||||
// 返回从左上角到 (i, j) 的最小路径代价
|
||||
return (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt()
|
||||
return min(left, up) + grid[i][j]
|
||||
}
|
||||
```
|
||||
|
||||
@ -711,8 +707,8 @@ $$
|
||||
```kotlin title="min_path_sum.kt"
|
||||
/* 最小路径和:记忆化搜索 */
|
||||
fun minPathSumDFSMem(
|
||||
grid: Array<Array<Int>>,
|
||||
mem: Array<Array<Int>>,
|
||||
grid: Array<IntArray>,
|
||||
mem: Array<IntArray>,
|
||||
i: Int,
|
||||
j: Int
|
||||
): Int {
|
||||
@ -732,7 +728,7 @@ $$
|
||||
val up = minPathSumDFSMem(grid, mem, i - 1, j)
|
||||
val left = minPathSumDFSMem(grid, mem, i, j - 1)
|
||||
// 记录并返回左上角到 (i, j) 的最小路径代价
|
||||
mem[i][j] = (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt()
|
||||
mem[i][j] = min(left, up) + grid[i][j]
|
||||
return mem[i][j]
|
||||
}
|
||||
```
|
||||
@ -1098,7 +1094,7 @@ $$
|
||||
|
||||
```kotlin title="min_path_sum.kt"
|
||||
/* 最小路径和:动态规划 */
|
||||
fun minPathSumDP(grid: Array<Array<Int>>): Int {
|
||||
fun minPathSumDP(grid: Array<IntArray>): Int {
|
||||
val n = grid.size
|
||||
val m = grid[0].size
|
||||
// 初始化 dp 表
|
||||
@ -1115,8 +1111,7 @@ $$
|
||||
// 状态转移:其余行和列
|
||||
for (i in 1..<n) {
|
||||
for (j in 1..<m) {
|
||||
dp[i][j] =
|
||||
(min(dp[i][j - 1].toDouble(), dp[i - 1][j].toDouble()) + grid[i][j]).toInt()
|
||||
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]
|
||||
}
|
||||
}
|
||||
return dp[n - 1][m - 1]
|
||||
@ -1500,7 +1495,7 @@ $$
|
||||
|
||||
```kotlin title="min_path_sum.kt"
|
||||
/* 最小路径和:空间优化后的动态规划 */
|
||||
fun minPathSumDPComp(grid: Array<Array<Int>>): Int {
|
||||
fun minPathSumDPComp(grid: Array<IntArray>): Int {
|
||||
val n = grid.size
|
||||
val m = grid[0].size
|
||||
// 初始化 dp 表
|
||||
@ -1516,7 +1511,7 @@ $$
|
||||
dp[0] = dp[0] + grid[i][0]
|
||||
// 状态转移:其余列
|
||||
for (j in 1..<m) {
|
||||
dp[j] = (min(dp[j - 1].toDouble(), dp[j].toDouble()) + grid[i][j]).toInt()
|
||||
dp[j] = min(dp[j - 1], dp[j]) + grid[i][j]
|
||||
}
|
||||
}
|
||||
return dp[m - 1]
|
||||
|
@ -443,11 +443,7 @@ $$
|
||||
dp[i][j] = dp[i - 1][j - 1]
|
||||
} else {
|
||||
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
|
||||
dp[i][j] =
|
||||
(min(
|
||||
min(dp[i][j - 1].toDouble(), dp[i - 1][j].toDouble()),
|
||||
dp[i - 1][j - 1].toDouble()
|
||||
) + 1).toInt()
|
||||
dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -941,7 +937,7 @@ $$
|
||||
dp[j] = leftup
|
||||
} else {
|
||||
// 最少编辑步数 = 插入、删除、替换这三种操作的最少编辑步数 + 1
|
||||
dp[j] = (min(min(dp[j - 1].toDouble(), dp[j].toDouble()), leftup.toDouble()) + 1).toInt()
|
||||
dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1
|
||||
}
|
||||
leftup = temp // 更新为下一轮的 dp[i-1, j-1]
|
||||
}
|
||||
|
@ -361,13 +361,14 @@ comments: true
|
||||
```kotlin title="climbing_stairs_backtrack.kt"
|
||||
/* 回溯 */
|
||||
fun backtrack(
|
||||
choices: List<Int>,
|
||||
choices: MutableList<Int>,
|
||||
state: Int,
|
||||
n: Int,
|
||||
res: MutableList<Int>
|
||||
) {
|
||||
// 当爬到第 n 阶时,方案数量加 1
|
||||
if (state == n) res[0] = res[0] + 1
|
||||
if (state == n)
|
||||
res[0] = res[0] + 1
|
||||
// 遍历所有选择
|
||||
for (choice in choices) {
|
||||
// 剪枝:不允许越过第 n 阶
|
||||
@ -382,7 +383,7 @@ comments: true
|
||||
fun climbingStairsBacktrack(n: Int): Int {
|
||||
val choices = mutableListOf(1, 2) // 可选择向上爬 1 阶或 2 阶
|
||||
val state = 0 // 从第 0 阶开始爬
|
||||
val res = ArrayList<Int>()
|
||||
val res = mutableListOf<Int>()
|
||||
res.add(0) // 使用 res[0] 记录方案数量
|
||||
backtrack(choices, state, n, res)
|
||||
return res[0]
|
||||
@ -1054,7 +1055,7 @@ $$
|
||||
fun climbingStairsDFSMem(n: Int): Int {
|
||||
// mem[i] 记录爬到第 i 阶的方案总数,-1 代表无记录
|
||||
val mem = IntArray(n + 1)
|
||||
Arrays.fill(mem, -1)
|
||||
mem.fill(-1)
|
||||
return dfs(n, mem)
|
||||
}
|
||||
```
|
||||
@ -1596,9 +1597,7 @@ $$
|
||||
var a = 1
|
||||
var b = 2
|
||||
for (i in 3..n) {
|
||||
val tmp = b
|
||||
b += a
|
||||
a = tmp
|
||||
b += a.also { a = b }
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ $$
|
||||
val no = knapsackDFS(wgt, value, i - 1, c)
|
||||
val yes = knapsackDFS(wgt, value, i - 1, c - wgt[i - 1]) + value[i - 1]
|
||||
// 返回两种方案中价值更大的那一个
|
||||
return max(no.toDouble(), yes.toDouble()).toInt()
|
||||
return max(no, yes)
|
||||
}
|
||||
```
|
||||
|
||||
@ -692,7 +692,7 @@ $$
|
||||
val no = knapsackDFSMem(wgt, value, mem, i - 1, c)
|
||||
val yes = knapsackDFSMem(wgt, value, mem, i - 1, c - wgt[i - 1]) + value[i - 1]
|
||||
// 记录并返回两种方案中价值更大的那一个
|
||||
mem[i][c] = max(no.toDouble(), yes.toDouble()).toInt()
|
||||
mem[i][c] = max(no, yes)
|
||||
return mem[i][c]
|
||||
}
|
||||
```
|
||||
@ -1052,8 +1052,7 @@ $$
|
||||
dp[i][c] = dp[i - 1][c]
|
||||
} else {
|
||||
// 不选和选物品 i 这两种方案的较大值
|
||||
dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i - 1][c - wgt[i - 1]] + value[i - 1]).toDouble())
|
||||
.toInt()
|
||||
dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + value[i - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1445,7 +1444,7 @@ $$
|
||||
if (wgt[i - 1] <= c) {
|
||||
// 不选和选物品 i 这两种方案的较大值
|
||||
dp[c] =
|
||||
max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
|
||||
max(dp[c], dp[c - wgt[i - 1]] + value[i - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,11 +327,7 @@ $$
|
||||
|
||||
```kotlin title="unbounded_knapsack.kt"
|
||||
/* 完全背包:动态规划 */
|
||||
fun unboundedKnapsackDP(
|
||||
wgt: IntArray,
|
||||
value: IntArray,
|
||||
cap: Int
|
||||
): Int {
|
||||
fun unboundedKnapsackDP(wgt: IntArray, value: IntArray, cap: Int): Int {
|
||||
val n = wgt.size
|
||||
// 初始化 dp 表
|
||||
val dp = Array(n + 1) { IntArray(cap + 1) }
|
||||
@ -343,8 +339,7 @@ $$
|
||||
dp[i][c] = dp[i - 1][c]
|
||||
} else {
|
||||
// 不选和选物品 i 这两种方案的较大值
|
||||
dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i][c - wgt[i - 1]] + value[i - 1]).toDouble())
|
||||
.toInt()
|
||||
dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + value[i - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -703,8 +698,7 @@ $$
|
||||
dp[c] = dp[c]
|
||||
} else {
|
||||
// 不选和选物品 i 这两种方案的较大值
|
||||
dp[c] =
|
||||
max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
|
||||
dp[c] = max(dp[c], dp[c - wgt[i - 1]] + value[i - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1154,8 +1148,7 @@ $$
|
||||
dp[i][a] = dp[i - 1][a]
|
||||
} else {
|
||||
// 不选和选硬币 i 这两种方案的较小值
|
||||
dp[i][a] = min(dp[i - 1][a].toDouble(), (dp[i][a - coins[i - 1]] + 1).toDouble())
|
||||
.toInt()
|
||||
dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1377,7 +1370,7 @@ $$
|
||||
}
|
||||
// 状态转移
|
||||
for i := 1; i <= n; i++ {
|
||||
// 倒序遍历
|
||||
// 正序遍历
|
||||
for a := 1; a <= amt; a++ {
|
||||
if coins[i-1] > a {
|
||||
// 若超过目标金额,则不选硬币 i
|
||||
@ -1568,7 +1561,7 @@ $$
|
||||
val MAX = amt + 1
|
||||
// 初始化 dp 表
|
||||
val dp = IntArray(amt + 1)
|
||||
Arrays.fill(dp, MAX)
|
||||
dp.fill(MAX)
|
||||
dp[0] = 0
|
||||
// 状态转移
|
||||
for (i in 1..n) {
|
||||
@ -1578,7 +1571,7 @@ $$
|
||||
dp[a] = dp[a]
|
||||
} else {
|
||||
// 不选和选硬币 i 这两种方案的较小值
|
||||
dp[a] = min(dp[a].toDouble(), (dp[a - coins[i - 1]] + 1).toDouble()).toInt()
|
||||
dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2150,7 +2143,7 @@ $$
|
||||
dp[0] = 1
|
||||
// 状态转移
|
||||
for i := 1; i <= n; i++ {
|
||||
// 倒序遍历
|
||||
// 正序遍历
|
||||
for a := 1; a <= amt; a++ {
|
||||
if coins[i-1] > a {
|
||||
// 若超过目标金额,则不选硬币 i
|
||||
|
@ -1044,10 +1044,10 @@ comments: true
|
||||
```kotlin title="graph_adjacency_matrix.kt"
|
||||
/* 基于邻接矩阵实现的无向图类 */
|
||||
class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
|
||||
val vertices: MutableList<Int> = ArrayList() // 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
|
||||
val adjMat: MutableList<MutableList<Int>> = ArrayList() // 邻接矩阵,行列索引对应“顶点索引”
|
||||
val vertices = mutableListOf<Int>() // 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
|
||||
val adjMat = mutableListOf<MutableList<Int>>() // 邻接矩阵,行列索引对应“顶点索引”
|
||||
|
||||
/* 构造函数 */
|
||||
/* 构造方法 */
|
||||
init {
|
||||
// 添加顶点
|
||||
for (vertex in vertices) {
|
||||
@ -1071,7 +1071,7 @@ comments: true
|
||||
// 向顶点列表中添加新顶点的值
|
||||
vertices.add(value)
|
||||
// 在邻接矩阵中添加一行
|
||||
val newRow: MutableList<Int> = mutableListOf()
|
||||
val newRow = mutableListOf<Int>()
|
||||
for (j in 0..<n) {
|
||||
newRow.add(0)
|
||||
}
|
||||
@ -1084,7 +1084,8 @@ comments: true
|
||||
|
||||
/* 删除顶点 */
|
||||
fun removeVertex(index: Int) {
|
||||
if (index >= size()) throw IndexOutOfBoundsException()
|
||||
if (index >= size())
|
||||
throw IndexOutOfBoundsException()
|
||||
// 在顶点列表中移除索引 index 的顶点
|
||||
vertices.removeAt(index)
|
||||
// 在邻接矩阵中删除索引 index 的行
|
||||
@ -1099,7 +1100,8 @@ comments: true
|
||||
// 参数 i, j 对应 vertices 元素索引
|
||||
fun addEdge(i: Int, j: Int) {
|
||||
// 索引越界与相等处理
|
||||
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
|
||||
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
|
||||
throw IndexOutOfBoundsException()
|
||||
// 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i)
|
||||
adjMat[i][j] = 1;
|
||||
adjMat[j][i] = 1;
|
||||
@ -1109,7 +1111,8 @@ comments: true
|
||||
// 参数 i, j 对应 vertices 元素索引
|
||||
fun removeEdge(i: Int, j: Int) {
|
||||
// 索引越界与相等处理
|
||||
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
|
||||
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
|
||||
throw IndexOutOfBoundsException()
|
||||
adjMat[i][j] = 0;
|
||||
adjMat[j][i] = 0;
|
||||
}
|
||||
@ -2158,9 +2161,9 @@ comments: true
|
||||
/* 基于邻接表实现的无向图类 */
|
||||
class GraphAdjList(edges: Array<Array<Vertex?>>) {
|
||||
// 邻接表,key:顶点,value:该顶点的所有邻接顶点
|
||||
val adjList: MutableMap<Vertex, MutableList<Vertex>> = HashMap()
|
||||
val adjList = HashMap<Vertex, MutableList<Vertex>>()
|
||||
|
||||
/* 构造函数 */
|
||||
/* 构造方法 */
|
||||
init {
|
||||
// 添加所有顶点和边
|
||||
for (edge in edges) {
|
||||
@ -2217,7 +2220,7 @@ comments: true
|
||||
fun print() {
|
||||
println("邻接表 =")
|
||||
for (pair in adjList.entries) {
|
||||
val tmp = ArrayList<Int>()
|
||||
val tmp = mutableListOf<Int>()
|
||||
for (vertex in pair.value) {
|
||||
tmp.add(vertex.value)
|
||||
}
|
||||
|
@ -418,24 +418,24 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
|
||||
```kotlin title="graph_bfs.kt"
|
||||
/* 广度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
fun graphBFS(graph: GraphAdjList, startVet: Vertex): List<Vertex> {
|
||||
fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList<Vertex?> {
|
||||
// 顶点遍历序列
|
||||
val res: MutableList<Vertex> = ArrayList()
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
val visited: MutableSet<Vertex> = HashSet()
|
||||
val visited = HashSet<Vertex>()
|
||||
visited.add(startVet)
|
||||
// 队列用于实现 BFS
|
||||
val que: Queue<Vertex> = LinkedList()
|
||||
val que = LinkedList<Vertex>()
|
||||
que.offer(startVet)
|
||||
// 以顶点 vet 为起点,循环直至访问完所有顶点
|
||||
while (!que.isEmpty()) {
|
||||
val vet = que.poll() // 队首顶点出队
|
||||
res.add(vet) // 记录访问顶点
|
||||
res.add(vet) // 记录访问顶点
|
||||
// 遍历该顶点的所有邻接顶点
|
||||
for (adjVet in graph.adjList[vet]!!) {
|
||||
if (visited.contains(adjVet)) continue // 跳过已被访问的顶点
|
||||
|
||||
que.offer(adjVet) // 只入队未访问的顶点
|
||||
if (visited.contains(adjVet))
|
||||
continue // 跳过已被访问的顶点
|
||||
que.offer(adjVet) // 只入队未访问的顶点
|
||||
visited.add(adjVet) // 标记该顶点已被访问
|
||||
}
|
||||
}
|
||||
@ -866,11 +866,12 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
|
||||
res: MutableList<Vertex?>,
|
||||
vet: Vertex?
|
||||
) {
|
||||
res.add(vet) // 记录访问顶点
|
||||
res.add(vet) // 记录访问顶点
|
||||
visited.add(vet) // 标记该顶点已被访问
|
||||
// 遍历该顶点的所有邻接顶点
|
||||
for (adjVet in graph.adjList[vet]!!) {
|
||||
if (visited.contains(adjVet)) continue // 跳过已被访问的顶点
|
||||
if (visited.contains(adjVet))
|
||||
continue // 跳过已被访问的顶点
|
||||
// 递归访问邻接顶点
|
||||
dfs(graph, visited, res, adjVet)
|
||||
}
|
||||
@ -878,14 +879,11 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
|
||||
|
||||
/* 深度优先遍历 */
|
||||
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
|
||||
fun graphDFS(
|
||||
graph: GraphAdjList,
|
||||
startVet: Vertex?
|
||||
): List<Vertex?> {
|
||||
fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList<Vertex?> {
|
||||
// 顶点遍历序列
|
||||
val res: MutableList<Vertex?> = ArrayList()
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 哈希表,用于记录已被访问过的顶点
|
||||
val visited: MutableSet<Vertex?> = HashSet()
|
||||
val visited = HashSet<Vertex?>()
|
||||
dfs(graph, visited, res, startVet)
|
||||
return res
|
||||
}
|
||||
|
@ -462,29 +462,25 @@ comments: true
|
||||
/* 物品 */
|
||||
class Item(
|
||||
val w: Int, // 物品
|
||||
val v: Int // 物品价值
|
||||
val v: Int // 物品价值
|
||||
)
|
||||
|
||||
/* 分数背包:贪心 */
|
||||
fun fractionalKnapsack(
|
||||
wgt: IntArray,
|
||||
value: IntArray,
|
||||
c: Int
|
||||
): Double {
|
||||
fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double {
|
||||
// 创建物品列表,包含两个属性:重量、价值
|
||||
var cap = c
|
||||
val items = arrayOfNulls<Item>(wgt.size)
|
||||
for (i in wgt.indices) {
|
||||
items[i] = Item(wgt[i], value[i])
|
||||
items[i] = Item(wgt[i], _val[i])
|
||||
}
|
||||
// 按照单位价值 item.v / item.w 从高到低进行排序
|
||||
Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) })
|
||||
items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) }
|
||||
// 循环贪心选择
|
||||
var res = 0.0
|
||||
for (item in items) {
|
||||
if (item!!.w <= cap) {
|
||||
// 若剩余容量充足,则将当前物品整个装进背包
|
||||
res += item.v.toDouble()
|
||||
res += item.v
|
||||
cap -= item.w
|
||||
} else {
|
||||
// 若剩余容量不足,则将当前物品的一部分装进背包
|
||||
@ -497,25 +493,21 @@ comments: true
|
||||
}
|
||||
|
||||
/* 分数背包:贪心 */
|
||||
fun fractionalKnapsack(
|
||||
wgt: IntArray,
|
||||
value: IntArray,
|
||||
c: Int
|
||||
): Double {
|
||||
fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double {
|
||||
// 创建物品列表,包含两个属性:重量、价值
|
||||
var cap = c
|
||||
val items = arrayOfNulls<Item>(wgt.size)
|
||||
for (i in wgt.indices) {
|
||||
items[i] = Item(wgt[i], value[i])
|
||||
items[i] = Item(wgt[i], _val[i])
|
||||
}
|
||||
// 按照单位价值 item.v / item.w 从高到低进行排序
|
||||
Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) })
|
||||
items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) }
|
||||
// 循环贪心选择
|
||||
var res = 0.0
|
||||
for (item in items) {
|
||||
if (item!!.w <= cap) {
|
||||
// 若剩余容量充足,则将当前物品整个装进背包
|
||||
res += item.v.toDouble()
|
||||
res += item.v
|
||||
cap -= item.w
|
||||
} else {
|
||||
// 若剩余容量不足,则将当前物品的一部分装进背包
|
||||
|
@ -381,8 +381,8 @@ $$
|
||||
// 循环贪心选择,直至两板相遇
|
||||
while (i < j) {
|
||||
// 更新最大容量
|
||||
val cap = (min(ht[i].toDouble(), ht[j].toDouble()) * (j - i)).toInt()
|
||||
res = max(res.toDouble(), cap.toDouble()).toInt()
|
||||
val cap = min(ht[i], ht[j]) * (j - i)
|
||||
res = max(res, cap)
|
||||
// 向内移动短板
|
||||
if (ht[i] < ht[j]) {
|
||||
i++
|
||||
|
@ -357,14 +357,14 @@ $$
|
||||
val b = n % 3
|
||||
if (b == 1) {
|
||||
// 当余数为 1 时,将一对 1 * 3 转化为 2 * 2
|
||||
return 3.0.pow((a - 1).toDouble()).toInt() * 2 * 2
|
||||
return 3.0.pow((a - 1)).toInt() * 2 * 2
|
||||
}
|
||||
if (b == 2) {
|
||||
// 当余数为 2 时,不做处理
|
||||
return 3.0.pow(a.toDouble()).toInt() * 2 * 2
|
||||
return 3.0.pow(a).toInt() * 2 * 2
|
||||
}
|
||||
// 当余数为 0 时,不做处理
|
||||
return 3.0.pow(a.toDouble()).toInt()
|
||||
return 3.0.pow(a).toInt()
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1114,17 +1114,14 @@ comments: true
|
||||
// 遍历桶,若遇到指定 key ,则更新对应 val 并返回
|
||||
for pair in bucket {
|
||||
if pair.key == key {
|
||||
pair.val = val.clone();
|
||||
pair.val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
let bucket = &mut self.buckets[index];
|
||||
|
||||
// 若无该 key ,则将键值对添加至尾部
|
||||
let pair = Pair {
|
||||
key,
|
||||
val: val.clone(),
|
||||
};
|
||||
let pair = Pair { key, val };
|
||||
bucket.push(pair);
|
||||
self.size += 1;
|
||||
}
|
||||
@ -1328,7 +1325,7 @@ comments: true
|
||||
capacity = 4
|
||||
loadThres = 2.0 / 3.0
|
||||
extendRatio = 2
|
||||
buckets = ArrayList(capacity)
|
||||
buckets = mutableListOf()
|
||||
for (i in 0..<capacity) {
|
||||
buckets.add(mutableListOf())
|
||||
}
|
||||
@ -2960,16 +2957,21 @@ comments: true
|
||||
```kotlin title="hash_map_open_addressing.kt"
|
||||
/* 开放寻址哈希表 */
|
||||
class HashMapOpenAddressing {
|
||||
private var size: Int = 0 // 键值对数量
|
||||
private var capacity = 4 // 哈希表容量
|
||||
private val loadThres: Double = 2.0 / 3.0 // 触发扩容的负载因子阈值
|
||||
private val extendRatio = 2 // 扩容倍数
|
||||
private var buckets: Array<Pair?> // 桶数组
|
||||
private val TOMBSTONE = Pair(-1, "-1") // 删除标记
|
||||
private var size: Int // 键值对数量
|
||||
private var capacity: Int // 哈希表容量
|
||||
private val loadThres: Double // 触发扩容的负载因子阈值
|
||||
private val extendRatio: Int // 扩容倍数
|
||||
private var buckets: Array<Pair?> // 桶数组
|
||||
private val TOMBSTONE: Pair // 删除标记
|
||||
|
||||
/* 构造方法 */
|
||||
init {
|
||||
size = 0
|
||||
capacity = 4
|
||||
loadThres = 2.0 / 3.0
|
||||
extendRatio = 2
|
||||
buckets = arrayOfNulls(capacity)
|
||||
TOMBSTONE = Pair(-1, "-1")
|
||||
}
|
||||
|
||||
/* 哈希函数 */
|
||||
|
@ -1589,15 +1589,9 @@ index = hash(key) % capacity
|
||||
|
||||
/* 基于数组实现的哈希表 */
|
||||
class ArrayHashMap {
|
||||
// 初始化数组,包含 100 个桶
|
||||
private val buckets = arrayOfNulls<Pair>(100)
|
||||
|
||||
init {
|
||||
// 初始化数组,包含 100 个桶
|
||||
for (i in 0..<100) {
|
||||
buckets[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
/* 哈希函数 */
|
||||
fun hashFunc(key: Int): Int {
|
||||
val index = key % 100
|
||||
@ -1627,25 +1621,27 @@ index = hash(key) % capacity
|
||||
|
||||
/* 获取所有键值对 */
|
||||
fun pairSet(): MutableList<Pair> {
|
||||
val pairSet = ArrayList<Pair>()
|
||||
val pairSet = mutableListOf<Pair>()
|
||||
for (pair in buckets) {
|
||||
if (pair != null) pairSet.add(pair)
|
||||
if (pair != null)
|
||||
pairSet.add(pair)
|
||||
}
|
||||
return pairSet
|
||||
}
|
||||
|
||||
/* 获取所有键 */
|
||||
fun keySet(): MutableList<Int> {
|
||||
val keySet = ArrayList<Int>()
|
||||
val keySet = mutableListOf<Int>()
|
||||
for (pair in buckets) {
|
||||
if (pair != null) keySet.add(pair.key)
|
||||
if (pair != null)
|
||||
keySet.add(pair.key)
|
||||
}
|
||||
return keySet
|
||||
}
|
||||
|
||||
/* 获取所有值 */
|
||||
fun valueSet(): MutableList<String> {
|
||||
val valueSet = ArrayList<String>()
|
||||
val valueSet = mutableListOf<String>()
|
||||
for (pair in buckets) {
|
||||
pair?.let { valueSet.add(it.value) }
|
||||
}
|
||||
@ -1657,22 +1653,16 @@ index = hash(key) % capacity
|
||||
for (kv in pairSet()) {
|
||||
val key = kv.key
|
||||
val value = kv.value
|
||||
println("${key}->${value}")
|
||||
println("${key} -> ${value}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 基于数组实现的哈希表 */
|
||||
class ArrayHashMap {
|
||||
// 初始化数组,包含 100 个桶
|
||||
private val buckets = arrayOfNulls<Pair>(100)
|
||||
|
||||
init {
|
||||
// 初始化数组,包含 100 个桶
|
||||
for (i in 0..<100) {
|
||||
buckets[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
/* 哈希函数 */
|
||||
fun hashFunc(key: Int): Int {
|
||||
val index = key % 100
|
||||
@ -1702,25 +1692,27 @@ index = hash(key) % capacity
|
||||
|
||||
/* 获取所有键值对 */
|
||||
fun pairSet(): MutableList<Pair> {
|
||||
val pairSet = ArrayList<Pair>()
|
||||
val pairSet = mutableListOf<Pair>()
|
||||
for (pair in buckets) {
|
||||
if (pair != null) pairSet.add(pair)
|
||||
if (pair != null)
|
||||
pairSet.add(pair)
|
||||
}
|
||||
return pairSet
|
||||
}
|
||||
|
||||
/* 获取所有键 */
|
||||
fun keySet(): MutableList<Int> {
|
||||
val keySet = ArrayList<Int>()
|
||||
val keySet = mutableListOf<Int>()
|
||||
for (pair in buckets) {
|
||||
if (pair != null) keySet.add(pair.key)
|
||||
if (pair != null)
|
||||
keySet.add(pair.key)
|
||||
}
|
||||
return keySet
|
||||
}
|
||||
|
||||
/* 获取所有值 */
|
||||
fun valueSet(): MutableList<String> {
|
||||
val valueSet = ArrayList<String>()
|
||||
val valueSet = mutableListOf<String>()
|
||||
for (pair in buckets) {
|
||||
pair?.let { valueSet.add(it.value) }
|
||||
}
|
||||
@ -1732,7 +1724,7 @@ index = hash(key) % capacity
|
||||
for (kv in pairSet()) {
|
||||
val key = kv.key
|
||||
val value = kv.value
|
||||
println("${key}->${value}")
|
||||
println("${key} -> ${value}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,13 +189,14 @@ comments: true
|
||||
|
||||
```kotlin title="my_heap.kt"
|
||||
/* 大顶堆 */
|
||||
class MaxHeap(nums: List<Int>?) {
|
||||
class MaxHeap(nums: MutableList<Int>?) {
|
||||
// 使用列表而非数组,这样无须考虑扩容问题
|
||||
// 将列表元素原封不动添加进堆
|
||||
private val maxHeap = ArrayList(nums!!)
|
||||
private val maxHeap = mutableListOf<Int>()
|
||||
|
||||
/* 构造函数,根据输入列表建堆 */
|
||||
/* 构造方法,根据输入列表建堆 */
|
||||
init {
|
||||
// 将列表元素原封不动添加进堆
|
||||
maxHeap.addAll(nums!!)
|
||||
// 堆化除叶节点以外的其他所有节点
|
||||
for (i in parent(size() - 1) downTo 0) {
|
||||
siftDown(i)
|
||||
|
@ -264,7 +264,7 @@ comments: true
|
||||
for (j in 0..<i) {
|
||||
if (nums[j] > nums[j + 1]) {
|
||||
// 交换 nums[j] 与 nums[j + 1]
|
||||
nums[j] = nums[j+1].also { nums[j+1] = nums[j] }
|
||||
nums[j] = nums[j + 1].also { nums[j + 1] = nums[j] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,9 +395,9 @@ comments: true
|
||||
fun bucketSort(nums: FloatArray) {
|
||||
// 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素
|
||||
val k = nums.size / 2
|
||||
val buckets = ArrayList<ArrayList<Float>>()
|
||||
val buckets = mutableListOf<MutableList<Float>>()
|
||||
for (i in 0..<k) {
|
||||
buckets.add(ArrayList())
|
||||
buckets.add(mutableListOf())
|
||||
}
|
||||
// 1. 将数组元素分配到各个桶中
|
||||
for (num in nums) {
|
||||
|
@ -324,7 +324,7 @@ comments: true
|
||||
// 1. 统计数组最大元素 m
|
||||
var m = 0
|
||||
for (num in nums) {
|
||||
m = max(m.toDouble(), num.toDouble()).toInt()
|
||||
m = max(m, num)
|
||||
}
|
||||
// 2. 统计各数字的出现次数
|
||||
// counter[num] 代表 num 的出现次数
|
||||
@ -822,7 +822,7 @@ $$
|
||||
// 1. 统计数组最大元素 m
|
||||
var m = 0
|
||||
for (num in nums) {
|
||||
m = max(m.toDouble(), num.toDouble()).toInt()
|
||||
m = max(m, num)
|
||||
}
|
||||
// 2. 统计各数字的出现次数
|
||||
// counter[num] 代表 num 的出现次数
|
||||
|
@ -545,10 +545,13 @@ comments: true
|
||||
val l = 2 * i + 1
|
||||
val r = 2 * i + 2
|
||||
var ma = i
|
||||
if (l < n && nums[l] > nums[ma]) ma = l
|
||||
if (r < n && nums[r] > nums[ma]) ma = r
|
||||
if (l < n && nums[l] > nums[ma])
|
||||
ma = l
|
||||
if (r < n && nums[r] > nums[ma])
|
||||
ma = r
|
||||
// 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出
|
||||
if (ma == i) break
|
||||
if (ma == i)
|
||||
break
|
||||
// 交换两节点
|
||||
nums[i] = nums[ma].also { nums[ma] = nums[i] }
|
||||
// 循环向下堆化
|
||||
|
@ -240,7 +240,7 @@ comments: true
|
||||
for (i in nums.indices) {
|
||||
val base = nums[i]
|
||||
var j = i - 1
|
||||
// 内循环: 将 base 插入到已排序部分的正确位置
|
||||
// 内循环:将 base 插入到已排序区间 [0, i-1] 中的正确位置
|
||||
while (j >= 0 && nums[j] > base) {
|
||||
nums[j + 1] = nums[j] // 将 nums[j] 向右移动一位
|
||||
j--
|
||||
|
@ -596,8 +596,10 @@ comments: true
|
||||
var k = 0
|
||||
// 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
|
||||
while (i <= mid && j <= right) {
|
||||
if (nums[i] <= nums[j]) tmp[k++] = nums[i++]
|
||||
else tmp[k++] = nums[j++]
|
||||
if (nums[i] <= nums[j])
|
||||
tmp[k++] = nums[i++]
|
||||
else
|
||||
tmp[k++] = nums[j++]
|
||||
}
|
||||
// 将左子数组和右子数组的剩余元素复制到临时数组中
|
||||
while (i <= mid) {
|
||||
|
@ -636,7 +636,7 @@ $$
|
||||
// 统计 0~9 各数字的出现次数
|
||||
for (i in 0..<n) {
|
||||
val d = digit(nums[i], exp) // 获取 nums[i] 第 k 位,记为 d
|
||||
counter[d]++ // 统计数字 d 的出现次数
|
||||
counter[d]++ // 统计数字 d 的出现次数
|
||||
}
|
||||
// 求前缀和,将“出现个数”转换为“数组索引”
|
||||
for (i in 1..9) {
|
||||
@ -647,11 +647,12 @@ $$
|
||||
for (i in n - 1 downTo 0) {
|
||||
val d = digit(nums[i], exp)
|
||||
val j = counter[d] - 1 // 获取 d 在数组中的索引 j
|
||||
res[j] = nums[i] // 将当前元素填入索引 j
|
||||
counter[d]-- // 将 d 的数量减 1
|
||||
res[j] = nums[i] // 将当前元素填入索引 j
|
||||
counter[d]-- // 将 d 的数量减 1
|
||||
}
|
||||
// 使用结果覆盖原数组 nums
|
||||
for (i in 0..<n) nums[i] = res[i]
|
||||
for (i in 0..<n)
|
||||
nums[i] = res[i]
|
||||
}
|
||||
|
||||
/* 基数排序 */
|
||||
|
@ -292,7 +292,8 @@ comments: true
|
||||
var k = i
|
||||
// 内循环:找到未排序区间内的最小元素
|
||||
for (j in i + 1..<n) {
|
||||
if (nums[j] < nums[k]) k = j // 记录最小元素的索引
|
||||
if (nums[j] < nums[k])
|
||||
k = j // 记录最小元素的索引
|
||||
}
|
||||
// 将该最小元素与未排序区间的首个元素交换
|
||||
nums[i] = nums[k].also { nums[k] = nums[i] }
|
||||
|
@ -38,25 +38,25 @@ comments: true
|
||||
|
||||
# 初始化双向队列
|
||||
deque: deque[int] = deque()
|
||||
|
||||
|
||||
# 元素入队
|
||||
deque.append(2) # 添加至队尾
|
||||
deque.append(5)
|
||||
deque.append(4)
|
||||
deque.appendleft(3) # 添加至队首
|
||||
deque.appendleft(1)
|
||||
|
||||
|
||||
# 访问元素
|
||||
front: int = deque[0] # 队首元素
|
||||
rear: int = deque[-1] # 队尾元素
|
||||
|
||||
|
||||
# 元素出队
|
||||
pop_front: int = deque.popleft() # 队首元素出队
|
||||
pop_rear: int = deque.pop() # 队尾元素出队
|
||||
|
||||
|
||||
# 获取双向队列的长度
|
||||
size: int = len(deque)
|
||||
|
||||
|
||||
# 判断双向队列是否为空
|
||||
is_empty: bool = len(deque) == 0
|
||||
```
|
||||
@ -66,25 +66,25 @@ comments: true
|
||||
```cpp title="deque.cpp"
|
||||
/* 初始化双向队列 */
|
||||
deque<int> deque;
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
deque.push_back(2); // 添加至队尾
|
||||
deque.push_back(5);
|
||||
deque.push_back(4);
|
||||
deque.push_front(3); // 添加至队首
|
||||
deque.push_front(1);
|
||||
|
||||
|
||||
/* 访问元素 */
|
||||
int front = deque.front(); // 队首元素
|
||||
int back = deque.back(); // 队尾元素
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
deque.pop_front(); // 队首元素出队
|
||||
deque.pop_back(); // 队尾元素出队
|
||||
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
int size = deque.size();
|
||||
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
bool empty = deque.empty();
|
||||
```
|
||||
@ -94,25 +94,25 @@ comments: true
|
||||
```java title="deque.java"
|
||||
/* 初始化双向队列 */
|
||||
Deque<Integer> deque = new LinkedList<>();
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
deque.offerLast(2); // 添加至队尾
|
||||
deque.offerLast(5);
|
||||
deque.offerLast(4);
|
||||
deque.offerFirst(3); // 添加至队首
|
||||
deque.offerFirst(1);
|
||||
|
||||
|
||||
/* 访问元素 */
|
||||
int peekFirst = deque.peekFirst(); // 队首元素
|
||||
int peekLast = deque.peekLast(); // 队尾元素
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
int popFirst = deque.pollFirst(); // 队首元素出队
|
||||
int popLast = deque.pollLast(); // 队尾元素出队
|
||||
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
int size = deque.size();
|
||||
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
boolean isEmpty = deque.isEmpty();
|
||||
```
|
||||
@ -123,25 +123,25 @@ comments: true
|
||||
/* 初始化双向队列 */
|
||||
// 在 C# 中,将链表 LinkedList 看作双向队列来使用
|
||||
LinkedList<int> deque = new();
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
deque.AddLast(2); // 添加至队尾
|
||||
deque.AddLast(5);
|
||||
deque.AddLast(4);
|
||||
deque.AddFirst(3); // 添加至队首
|
||||
deque.AddFirst(1);
|
||||
|
||||
|
||||
/* 访问元素 */
|
||||
int peekFirst = deque.First.Value; // 队首元素
|
||||
int peekLast = deque.Last.Value; // 队尾元素
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
deque.RemoveFirst(); // 队首元素出队
|
||||
deque.RemoveLast(); // 队尾元素出队
|
||||
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
int size = deque.Count;
|
||||
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
bool isEmpty = deque.Count == 0;
|
||||
```
|
||||
@ -152,25 +152,25 @@ comments: true
|
||||
/* 初始化双向队列 */
|
||||
// 在 Go 中,将 list 作为双向队列使用
|
||||
deque := list.New()
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
deque.PushBack(2) // 添加至队尾
|
||||
deque.PushBack(5)
|
||||
deque.PushBack(4)
|
||||
deque.PushFront(3) // 添加至队首
|
||||
deque.PushFront(1)
|
||||
|
||||
|
||||
/* 访问元素 */
|
||||
front := deque.Front() // 队首元素
|
||||
rear := deque.Back() // 队尾元素
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
deque.Remove(front) // 队首元素出队
|
||||
deque.Remove(rear) // 队尾元素出队
|
||||
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
size := deque.Len()
|
||||
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
isEmpty := deque.Len() == 0
|
||||
```
|
||||
@ -339,25 +339,25 @@ comments: true
|
||||
```kotlin title="deque.kt"
|
||||
/* 初始化双向队列 */
|
||||
val deque = LinkedList<Int>()
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
deque.offerLast(2) // 添加至队尾
|
||||
deque.offerLast(5)
|
||||
deque.offerLast(4)
|
||||
deque.offerFirst(3) // 添加至队首
|
||||
deque.offerFirst(1)
|
||||
|
||||
|
||||
/* 访问元素 */
|
||||
val peekFirst = deque.peekFirst() // 队首元素
|
||||
val peekLast = deque.peekLast() // 队尾元素
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
val popFirst = deque.pollFirst() // 队首元素出队
|
||||
val popLast = deque.pollLast() // 队尾元素出队
|
||||
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
val size = deque.size
|
||||
|
||||
|
||||
/* 判断双向队列是否为空 */
|
||||
val isEmpty = deque.isEmpty()
|
||||
```
|
||||
@ -365,7 +365,32 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="deque.rb"
|
||||
# 初始化双向队列
|
||||
# Ruby 没有内直的双端队列,只能把 Array 当作双端队列来使用
|
||||
deque = []
|
||||
|
||||
# 元素如队
|
||||
deque << 2
|
||||
deque << 5
|
||||
deque << 4
|
||||
# 请注意,由于是数组,Array#unshift 方法的时间复杂度为 O(n)
|
||||
deque.unshift(3)
|
||||
deque.unshift(1)
|
||||
|
||||
# 访问元素
|
||||
peek_first = deque.first
|
||||
peek_last = deque.last
|
||||
|
||||
# 元素出队
|
||||
# 请注意,由于是数组, Array#shift 方法的时间复杂度为 O(n)
|
||||
pop_front = deque.shift
|
||||
pop_back = deque.pop
|
||||
|
||||
# 获取双向队列的长度
|
||||
size = deque.length
|
||||
|
||||
# 判断双向队列是否为空
|
||||
is_empty = size.zero?
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1874,7 +1899,7 @@ comments: true
|
||||
|
||||
```kotlin title="linkedlist_deque.kt"
|
||||
/* 双向链表节点 */
|
||||
class ListNode(var value: Int) {
|
||||
class ListNode(var _val: Int) {
|
||||
// 节点值
|
||||
var next: ListNode? = null // 后继节点引用
|
||||
var prev: ListNode? = null // 前驱节点引用
|
||||
@ -1882,9 +1907,9 @@ comments: true
|
||||
|
||||
/* 基于双向链表实现的双向队列 */
|
||||
class LinkedListDeque {
|
||||
private var front: ListNode? = null // 头节点 front ,尾节点 rear
|
||||
private var rear: ListNode? = null
|
||||
private var queSize = 0 // 双向队列的长度
|
||||
private var front: ListNode? = null // 头节点 front
|
||||
private var rear: ListNode? = null // 尾节点 rear
|
||||
private var queSize: Int = 0 // 双向队列的长度
|
||||
|
||||
/* 获取双向队列的长度 */
|
||||
fun size(): Int {
|
||||
@ -1931,12 +1956,12 @@ comments: true
|
||||
|
||||
/* 出队操作 */
|
||||
fun pop(isFront: Boolean): Int {
|
||||
if (isEmpty()) throw IndexOutOfBoundsException()
|
||||
|
||||
if (isEmpty())
|
||||
throw IndexOutOfBoundsException()
|
||||
val value: Int
|
||||
// 队首出队操作
|
||||
if (isFront) {
|
||||
value = front!!.value // 暂存头节点值
|
||||
value = front!!._val // 暂存头节点值
|
||||
// 删除头节点
|
||||
val fNext = front!!.next
|
||||
if (fNext != null) {
|
||||
@ -1946,7 +1971,7 @@ comments: true
|
||||
front = fNext // 更新头节点
|
||||
// 队尾出队操作
|
||||
} else {
|
||||
value = rear!!.value // 暂存尾节点值
|
||||
value = rear!!._val // 暂存尾节点值
|
||||
// 删除尾节点
|
||||
val rPrev = rear!!.prev
|
||||
if (rPrev != null) {
|
||||
@ -1971,17 +1996,14 @@ comments: true
|
||||
|
||||
/* 访问队首元素 */
|
||||
fun peekFirst(): Int {
|
||||
if (isEmpty()) {
|
||||
throw IndexOutOfBoundsException()
|
||||
|
||||
}
|
||||
return front!!.value
|
||||
if (isEmpty()) throw IndexOutOfBoundsException()
|
||||
return front!!._val
|
||||
}
|
||||
|
||||
/* 访问队尾元素 */
|
||||
fun peekLast(): Int {
|
||||
if (isEmpty()) throw IndexOutOfBoundsException()
|
||||
return rear!!.value
|
||||
return rear!!._val
|
||||
}
|
||||
|
||||
/* 返回数组用于打印 */
|
||||
@ -1989,7 +2011,7 @@ comments: true
|
||||
var node = front
|
||||
val res = IntArray(size())
|
||||
for (i in res.indices) {
|
||||
res[i] = node!!.value
|
||||
res[i] = node!!._val
|
||||
node = node.next
|
||||
}
|
||||
return res
|
||||
@ -2000,9 +2022,138 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="linkedlist_deque.rb"
|
||||
[class]{ListNode}-[func]{}
|
||||
=begin
|
||||
File: linkedlist_deque.rb
|
||||
Created Time: 2024-04-06
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
[class]{LinkedListDeque}-[func]{}
|
||||
### 双向链表节点
|
||||
class ListNode
|
||||
attr_accessor :val
|
||||
attr_accessor :next # 后继节点引用
|
||||
attr_accessor :prev # 前躯节点引用
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize(val)
|
||||
@val = val
|
||||
end
|
||||
end
|
||||
|
||||
### 基于双向链表实现的双向队列 ###
|
||||
class LinkedListDeque
|
||||
### 获取双向队列的长度 ###
|
||||
attr_reader :size
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize
|
||||
@front = nil # 头节点 front
|
||||
@rear = nil # 尾节点 rear
|
||||
@size = 0 # 双向队列的长度
|
||||
end
|
||||
|
||||
### 判断双向队列是否为空 ###
|
||||
def is_empty?
|
||||
size.zero?
|
||||
end
|
||||
|
||||
### 入队操作 ###
|
||||
def push(num, is_front)
|
||||
node = ListNode.new(num)
|
||||
# 若链表为空, 则令 front 和 rear 都指向 node
|
||||
if is_empty?
|
||||
@front = @rear = node
|
||||
# 队首入队操作
|
||||
elsif is_front
|
||||
# 将 node 添加至链表头部
|
||||
@front.prev = node
|
||||
node.next = @front
|
||||
@front = node # 更新头节点
|
||||
# 队尾入队操作
|
||||
else
|
||||
# 将 node 添加至链表尾部
|
||||
@rear.next = node
|
||||
node.prev = @rear
|
||||
@rear = node # 更新尾节点
|
||||
end
|
||||
@size += 1 # 更新队列长度
|
||||
end
|
||||
|
||||
### 队首入队 ###
|
||||
def push_first(num)
|
||||
push(num, true)
|
||||
end
|
||||
|
||||
### 队尾入队 ###
|
||||
def push_last(num)
|
||||
push(num, false)
|
||||
end
|
||||
|
||||
### 出队操作 ###
|
||||
def pop(is_front)
|
||||
raise IndexError, '双向队列为空' if is_empty?
|
||||
|
||||
# 队首出队操作
|
||||
if is_front
|
||||
val = @front.val # 暂存头节点值
|
||||
# 删除头节点
|
||||
fnext = @front.next
|
||||
unless fnext.nil?
|
||||
fnext.prev = nil
|
||||
@front.next = nil
|
||||
end
|
||||
@front = fnext # 更新头节点
|
||||
# 队尾出队操作
|
||||
else
|
||||
val = @rear.val # 暂存尾节点值
|
||||
# 删除尾节点
|
||||
rprev = @rear.prev
|
||||
unless rprev.nil?
|
||||
rprev.next = nil
|
||||
@rear.prev = nil
|
||||
end
|
||||
@rear = rprev # 更新尾节点
|
||||
end
|
||||
@size -= 1 # 更新队列长度
|
||||
|
||||
val
|
||||
end
|
||||
|
||||
### 队首出队 ###
|
||||
def pop_first
|
||||
pop(true)
|
||||
end
|
||||
|
||||
### 队首出队 ###
|
||||
def pop_last
|
||||
pop(false)
|
||||
end
|
||||
|
||||
### 访问队首元素 ###
|
||||
def peek_first
|
||||
raise IndexError, '双向队列为空' if is_empty?
|
||||
|
||||
@front.val
|
||||
end
|
||||
|
||||
### 访问队尾元素 ###
|
||||
def peek_last
|
||||
raise IndexError, '双向队列为空' if is_empty?
|
||||
|
||||
@rear.val
|
||||
end
|
||||
|
||||
### 返回数组用于打印 ###
|
||||
def to_array
|
||||
node = @front
|
||||
res = Array.new(size, 0)
|
||||
for i in 0...size
|
||||
res[i] = node.val
|
||||
node = node.next
|
||||
end
|
||||
res
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -3385,11 +3536,11 @@ comments: true
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title="array_deque.kt"
|
||||
/* 基于环形数组实现的双向队列 */
|
||||
/* 构造方法 */
|
||||
class ArrayDeque(capacity: Int) {
|
||||
private var nums = IntArray(capacity) // 用于存储双向队列元素的数组
|
||||
private var front = 0 // 队首指针,指向队首元素
|
||||
private var queSize = 0 // 双向队列长度
|
||||
private var nums: IntArray = IntArray(capacity) // 用于存储双向队列元素的数组
|
||||
private var front: Int = 0 // 队首指针,指向队首元素
|
||||
private var queSize: Int = 0 // 双向队列长度
|
||||
|
||||
/* 获取双向队列的容量 */
|
||||
fun capacity(): Int {
|
||||
@ -3450,7 +3601,7 @@ comments: true
|
||||
return num
|
||||
}
|
||||
|
||||
/* 访问队尾元素 */
|
||||
/* 队尾出队 */
|
||||
fun popLast(): Int {
|
||||
val num = peekLast()
|
||||
queSize--
|
||||
@ -3490,7 +3641,109 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="array_deque.rb"
|
||||
[class]{ArrayDeque}-[func]{}
|
||||
### 基于环形数组实现的双向队列 ###
|
||||
class ArrayDeque
|
||||
### 获取双向队列的长度 ###
|
||||
attr_reader :size
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize(capacity)
|
||||
@nums = Array.new(capacity, 0)
|
||||
@front = 0
|
||||
@size = 0
|
||||
end
|
||||
|
||||
### 获取双向队列的容量 ###
|
||||
def capacity
|
||||
@nums.length
|
||||
end
|
||||
|
||||
### 判断双向队列是否为空 ###
|
||||
def is_empty?
|
||||
size.zero?
|
||||
end
|
||||
|
||||
### 队首入队 ###
|
||||
def push_first(num)
|
||||
if size == capacity
|
||||
puts '双向队列已满'
|
||||
return
|
||||
end
|
||||
|
||||
# 队首指针向左移动一位
|
||||
# 通过取余操作实现 front 越过数组头部后回到尾部
|
||||
@front = index(@front - 1)
|
||||
# 将 num 添加至队首
|
||||
@nums[@front] = num
|
||||
@size += 1
|
||||
end
|
||||
|
||||
### 队尾入队 ###
|
||||
def push_last(num)
|
||||
if size == capacity
|
||||
puts '双向队列已满'
|
||||
return
|
||||
end
|
||||
|
||||
# 计算队尾指针,指向队尾索引 + 1
|
||||
rear = index(@front + size)
|
||||
# 将 num 添加至队尾
|
||||
@nums[rear] = num
|
||||
@size += 1
|
||||
end
|
||||
|
||||
### 队首出队 ###
|
||||
def pop_first
|
||||
num = peek_first
|
||||
# 队首指针向后移动一位
|
||||
@front = index(@front + 1)
|
||||
@size -= 1
|
||||
num
|
||||
end
|
||||
|
||||
### 队尾出队 ###
|
||||
def pop_last
|
||||
num = peek_last
|
||||
@size -= 1
|
||||
num
|
||||
end
|
||||
|
||||
### 访问队首元素 ###
|
||||
def peek_first
|
||||
raise IndexError, '双向队列为空' if is_empty?
|
||||
|
||||
@nums[@front]
|
||||
end
|
||||
|
||||
### 访问队尾元素 ###
|
||||
def peek_last
|
||||
raise IndexError, '双向队列为空' if is_empty?
|
||||
|
||||
# 计算尾元素索引
|
||||
last = index(@front + size - 1)
|
||||
@nums[last]
|
||||
end
|
||||
|
||||
### 返回数组用于打印 ###
|
||||
def to_array
|
||||
# 仅转换有效长度范围内的列表元素
|
||||
res = []
|
||||
for i in 0...size
|
||||
res << @nums[index(@front + i)]
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
### 计算环形数组索引 ###
|
||||
def index(i)
|
||||
# 通过取余操作实现数组首尾相连
|
||||
# 当 i 越过数组尾部后,回到头部
|
||||
# 当 i 越过数组头部后,回到尾部
|
||||
(i + capacity) % capacity
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -39,23 +39,23 @@ comments: true
|
||||
# 在 Python 中,我们一般将双向队列类 deque 当作队列使用
|
||||
# 虽然 queue.Queue() 是纯正的队列类,但不太好用,因此不推荐
|
||||
que: deque[int] = deque()
|
||||
|
||||
|
||||
# 元素入队
|
||||
que.append(1)
|
||||
que.append(3)
|
||||
que.append(2)
|
||||
que.append(5)
|
||||
que.append(4)
|
||||
|
||||
|
||||
# 访问队首元素
|
||||
front: int = que[0]
|
||||
|
||||
|
||||
# 元素出队
|
||||
pop: int = que.popleft()
|
||||
|
||||
|
||||
# 获取队列的长度
|
||||
size: int = len(que)
|
||||
|
||||
|
||||
# 判断队列是否为空
|
||||
is_empty: bool = len(que) == 0
|
||||
```
|
||||
@ -65,23 +65,23 @@ comments: true
|
||||
```cpp title="queue.cpp"
|
||||
/* 初始化队列 */
|
||||
queue<int> queue;
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.push(1);
|
||||
queue.push(3);
|
||||
queue.push(2);
|
||||
queue.push(5);
|
||||
queue.push(4);
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
int front = queue.front();
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
queue.pop();
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
int size = queue.size();
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool empty = queue.empty();
|
||||
```
|
||||
@ -91,23 +91,23 @@ comments: true
|
||||
```java title="queue.java"
|
||||
/* 初始化队列 */
|
||||
Queue<Integer> queue = new LinkedList<>();
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.offer(1);
|
||||
queue.offer(3);
|
||||
queue.offer(2);
|
||||
queue.offer(5);
|
||||
queue.offer(4);
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
int peek = queue.peek();
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
int pop = queue.poll();
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
int size = queue.size();
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
boolean isEmpty = queue.isEmpty();
|
||||
```
|
||||
@ -117,23 +117,23 @@ comments: true
|
||||
```csharp title="queue.cs"
|
||||
/* 初始化队列 */
|
||||
Queue<int> queue = new();
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.Enqueue(1);
|
||||
queue.Enqueue(3);
|
||||
queue.Enqueue(2);
|
||||
queue.Enqueue(5);
|
||||
queue.Enqueue(4);
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
int peek = queue.Peek();
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
int pop = queue.Dequeue();
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
int size = queue.Count;
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
bool isEmpty = queue.Count == 0;
|
||||
```
|
||||
@ -144,24 +144,24 @@ comments: true
|
||||
/* 初始化队列 */
|
||||
// 在 Go 中,将 list 作为队列来使用
|
||||
queue := list.New()
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.PushBack(1)
|
||||
queue.PushBack(3)
|
||||
queue.PushBack(2)
|
||||
queue.PushBack(5)
|
||||
queue.PushBack(4)
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
peek := queue.Front()
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
pop := queue.Front()
|
||||
queue.Remove(pop)
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
size := queue.Len()
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
isEmpty := queue.Len() == 0
|
||||
```
|
||||
@ -172,24 +172,24 @@ comments: true
|
||||
/* 初始化队列 */
|
||||
// Swift 没有内置的队列类,可以把 Array 当作队列来使用
|
||||
var queue: [Int] = []
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.append(1)
|
||||
queue.append(3)
|
||||
queue.append(2)
|
||||
queue.append(5)
|
||||
queue.append(4)
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
let peek = queue.first!
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
// 由于是数组,因此 removeFirst 的复杂度为 O(n)
|
||||
let pool = queue.removeFirst()
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
let size = queue.count
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
let isEmpty = queue.isEmpty
|
||||
```
|
||||
@ -200,24 +200,24 @@ comments: true
|
||||
/* 初始化队列 */
|
||||
// JavaScript 没有内置的队列,可以把 Array 当作队列来使用
|
||||
const queue = [];
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.push(1);
|
||||
queue.push(3);
|
||||
queue.push(2);
|
||||
queue.push(5);
|
||||
queue.push(4);
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
const peek = queue[0];
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
// 底层是数组,因此 shift() 方法的时间复杂度为 O(n)
|
||||
const pop = queue.shift();
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
const size = queue.length;
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
const empty = queue.length === 0;
|
||||
```
|
||||
@ -226,26 +226,26 @@ comments: true
|
||||
|
||||
```typescript title="queue.ts"
|
||||
/* 初始化队列 */
|
||||
// TypeScript 没有内置的队列,可以把 Array 当作队列来使用
|
||||
// TypeScript 没有内置的队列,可以把 Array 当作队列来使用
|
||||
const queue: number[] = [];
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.push(1);
|
||||
queue.push(3);
|
||||
queue.push(2);
|
||||
queue.push(5);
|
||||
queue.push(4);
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
const peek = queue[0];
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
// 底层是数组,因此 shift() 方法的时间复杂度为 O(n)
|
||||
const pop = queue.shift();
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
const size = queue.length;
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
const empty = queue.length === 0;
|
||||
```
|
||||
@ -317,23 +317,23 @@ comments: true
|
||||
```kotlin title="queue.kt"
|
||||
/* 初始化队列 */
|
||||
val queue = LinkedList<Int>()
|
||||
|
||||
|
||||
/* 元素入队 */
|
||||
queue.offer(1)
|
||||
queue.offer(3)
|
||||
queue.offer(2)
|
||||
queue.offer(5)
|
||||
queue.offer(4)
|
||||
|
||||
|
||||
/* 访问队首元素 */
|
||||
val peek = queue.peek()
|
||||
|
||||
|
||||
/* 元素出队 */
|
||||
val pop = queue.poll()
|
||||
|
||||
|
||||
/* 获取队列的长度 */
|
||||
val size = queue.size
|
||||
|
||||
|
||||
/* 判断队列是否为空 */
|
||||
val isEmpty = queue.isEmpty()
|
||||
```
|
||||
@ -341,7 +341,29 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="queue.rb"
|
||||
# 初始化队列
|
||||
# Ruby 内置的队列(Thread::Queue) 没有 peek 和遍历方法,可以把 Array 当作队列来使用
|
||||
queue = []
|
||||
|
||||
# 元素入队
|
||||
queue.push(1)
|
||||
queue.push(3)
|
||||
queue.push(2)
|
||||
queue.push(5)
|
||||
queue.push(4)
|
||||
|
||||
# 访问队列元素
|
||||
peek = queue.first
|
||||
|
||||
# 元素出队
|
||||
# 清注意,由于是数组,Array#shift 方法时间复杂度为 O(n)
|
||||
pop = queue.shift
|
||||
|
||||
# 获取队列的长度
|
||||
size = queue.length
|
||||
|
||||
# 判断队列是否为空
|
||||
is_empty = queue.empty?
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1206,7 +1228,7 @@ comments: true
|
||||
/* 访问队首元素 */
|
||||
fun peek(): Int {
|
||||
if (isEmpty()) throw IndexOutOfBoundsException()
|
||||
return front!!.value
|
||||
return front!!._val
|
||||
}
|
||||
|
||||
/* 将链表转化为 Array 并返回 */
|
||||
@ -1214,7 +1236,7 @@ comments: true
|
||||
var node = front
|
||||
val res = IntArray(size())
|
||||
for (i in res.indices) {
|
||||
res[i] = node!!.value
|
||||
res[i] = node!!._val
|
||||
node = node.next
|
||||
}
|
||||
return res
|
||||
@ -1225,7 +1247,68 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="linkedlist_queue.rb"
|
||||
[class]{LinkedListQueue}-[func]{}
|
||||
### 基于链表头现的队列 ###
|
||||
class LinkedListQueue
|
||||
### 获取队列的长度 ###
|
||||
attr_reader :size
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize
|
||||
@front = nil # 头节点 front
|
||||
@rear = nil # 尾节点 rear
|
||||
@size = 0
|
||||
end
|
||||
|
||||
### 判断队列是否为空 ###
|
||||
def is_empty?
|
||||
@front.nil?
|
||||
end
|
||||
|
||||
### 入队 ###
|
||||
def push(num)
|
||||
# 在尾节点后添加 num
|
||||
node = ListNode.new(num)
|
||||
|
||||
# 如果队列为空,则令头,尾节点都指向该节点
|
||||
if @front.nil?
|
||||
@front = node
|
||||
@rear = node
|
||||
# 如果队列不为空,则令该节点添加到尾节点后
|
||||
else
|
||||
@rear.next = node
|
||||
@rear = node
|
||||
end
|
||||
|
||||
@size += 1
|
||||
end
|
||||
|
||||
### 出队 ###
|
||||
def pop
|
||||
num = peek
|
||||
# 删除头节点
|
||||
@front = @front.next
|
||||
@size -= 1
|
||||
num
|
||||
end
|
||||
|
||||
### 访问队首元素 ###
|
||||
def peek
|
||||
raise IndexError, '队列为空' if is_empty?
|
||||
|
||||
@front.val
|
||||
end
|
||||
|
||||
### 将链表为 Array 并返回 ###
|
||||
def to_array
|
||||
queue = []
|
||||
temp = @front
|
||||
while temp
|
||||
queue << temp.val
|
||||
temp = temp.next
|
||||
end
|
||||
queue
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -2144,9 +2227,9 @@ comments: true
|
||||
```kotlin title="array_queue.kt"
|
||||
/* 基于环形数组实现的队列 */
|
||||
class ArrayQueue(capacity: Int) {
|
||||
private val nums = IntArray(capacity) // 用于存储队列元素的数组
|
||||
private var front = 0 // 队首指针,指向队首元素
|
||||
private var queSize = 0 // 队列长度
|
||||
private val nums: IntArray = IntArray(capacity) // 用于存储队列元素的数组
|
||||
private var front: Int = 0 // 队首指针,指向队首元素
|
||||
private var queSize: Int = 0 // 队列长度
|
||||
|
||||
/* 获取队列的容量 */
|
||||
fun capacity(): Int {
|
||||
@ -2211,7 +2294,69 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="array_queue.rb"
|
||||
[class]{ArrayQueue}-[func]{}
|
||||
### 基于环形数组实现的队列 ###
|
||||
class ArrayQueue
|
||||
### 获取队列的长度 ###
|
||||
attr_reader :size
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize(size)
|
||||
@nums = Array.new(size, 0) # 用于存储队列元素的数组
|
||||
@front = 0 # 队首指针,指向队首元素
|
||||
@size = 0 # 队列长度
|
||||
end
|
||||
|
||||
### 获取队列的容量 ###
|
||||
def capacity
|
||||
@nums.length
|
||||
end
|
||||
|
||||
### 判断队列是否为空 ###
|
||||
def is_empty?
|
||||
size.zero?
|
||||
end
|
||||
|
||||
### 入队 ###
|
||||
def push(num)
|
||||
raise IndexError, '队列已满' if size == capacity
|
||||
|
||||
# 计算队尾指针,指向队尾索引 + 1
|
||||
# 通过取余操作实现 rear 越过数组尾部后回到头部
|
||||
rear = (@front + size) % capacity
|
||||
# 将 num 添加至队尾
|
||||
@nums[rear] = num
|
||||
@size += 1
|
||||
end
|
||||
|
||||
### 出队 ###
|
||||
def pop
|
||||
num = peek
|
||||
# 队首指针向后移动一位,若越过尾部,则返回到数组头部
|
||||
@front = (@front + 1) % capacity
|
||||
@size -= 1
|
||||
num
|
||||
end
|
||||
|
||||
### 访问队首元素 ###
|
||||
def peek
|
||||
raise IndexError, '队列为空' if is_empty?
|
||||
|
||||
@nums[@front]
|
||||
end
|
||||
|
||||
### 返回列表用于打印 ###
|
||||
def to_array
|
||||
res = Array.new(size, 0)
|
||||
j = @front
|
||||
|
||||
for i in 0...size
|
||||
res[i] = @nums[j % capacity]
|
||||
j += 1
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -36,25 +36,25 @@ comments: true
|
||||
|
||||
```python title="stack.py"
|
||||
# 初始化栈
|
||||
# Python 没有内置的栈类,可以把 list 当作栈来使用
|
||||
# Python 没有内置的栈类,可以把 list 当作栈来使用
|
||||
stack: list[int] = []
|
||||
|
||||
|
||||
# 元素入栈
|
||||
stack.append(1)
|
||||
stack.append(3)
|
||||
stack.append(2)
|
||||
stack.append(5)
|
||||
stack.append(4)
|
||||
|
||||
|
||||
# 访问栈顶元素
|
||||
peek: int = stack[-1]
|
||||
|
||||
|
||||
# 元素出栈
|
||||
pop: int = stack.pop()
|
||||
|
||||
|
||||
# 获取栈的长度
|
||||
size: int = len(stack)
|
||||
|
||||
|
||||
# 判断是否为空
|
||||
is_empty: bool = len(stack) == 0
|
||||
```
|
||||
@ -64,23 +64,23 @@ comments: true
|
||||
```cpp title="stack.cpp"
|
||||
/* 初始化栈 */
|
||||
stack<int> stack;
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
int top = stack.top();
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
stack.pop(); // 无返回值
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
int size = stack.size();
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
bool empty = stack.empty();
|
||||
```
|
||||
@ -116,23 +116,23 @@ comments: true
|
||||
```csharp title="stack.cs"
|
||||
/* 初始化栈 */
|
||||
Stack<int> stack = new();
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.Push(1);
|
||||
stack.Push(3);
|
||||
stack.Push(2);
|
||||
stack.Push(5);
|
||||
stack.Push(4);
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
int peek = stack.Peek();
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
int pop = stack.Pop();
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
int size = stack.Count;
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
bool isEmpty = stack.Count == 0;
|
||||
```
|
||||
@ -143,24 +143,24 @@ comments: true
|
||||
/* 初始化栈 */
|
||||
// 在 Go 中,推荐将 Slice 当作栈来使用
|
||||
var stack []int
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack = append(stack, 1)
|
||||
stack = append(stack, 3)
|
||||
stack = append(stack, 2)
|
||||
stack = append(stack, 5)
|
||||
stack = append(stack, 4)
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
peek := stack[len(stack)-1]
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
pop := stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
size := len(stack)
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
isEmpty := len(stack) == 0
|
||||
```
|
||||
@ -171,23 +171,23 @@ comments: true
|
||||
/* 初始化栈 */
|
||||
// Swift 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
var stack: [Int] = []
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.append(1)
|
||||
stack.append(3)
|
||||
stack.append(2)
|
||||
stack.append(5)
|
||||
stack.append(4)
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
let peek = stack.last!
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
let pop = stack.removeLast()
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
let size = stack.count
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
let isEmpty = stack.isEmpty
|
||||
```
|
||||
@ -196,25 +196,25 @@ comments: true
|
||||
|
||||
```javascript title="stack.js"
|
||||
/* 初始化栈 */
|
||||
// JavaScript 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
// JavaScript 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
const stack = [];
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
const peek = stack[stack.length-1];
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
const pop = stack.pop();
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
const size = stack.length;
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
const is_empty = stack.length === 0;
|
||||
```
|
||||
@ -223,25 +223,25 @@ comments: true
|
||||
|
||||
```typescript title="stack.ts"
|
||||
/* 初始化栈 */
|
||||
// TypeScript 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
// TypeScript 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
const stack: number[] = [];
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
const peek = stack[stack.length - 1];
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
const pop = stack.pop();
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
const size = stack.length;
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
const is_empty = stack.length === 0;
|
||||
```
|
||||
@ -311,23 +311,23 @@ comments: true
|
||||
```kotlin title="stack.kt"
|
||||
/* 初始化栈 */
|
||||
val stack = Stack<Int>()
|
||||
|
||||
|
||||
/* 元素入栈 */
|
||||
stack.push(1)
|
||||
stack.push(3)
|
||||
stack.push(2)
|
||||
stack.push(5)
|
||||
stack.push(4)
|
||||
|
||||
|
||||
/* 访问栈顶元素 */
|
||||
val peek = stack.peek()
|
||||
|
||||
|
||||
/* 元素出栈 */
|
||||
val pop = stack.pop()
|
||||
|
||||
|
||||
/* 获取栈的长度 */
|
||||
val size = stack.size
|
||||
|
||||
|
||||
/* 判断是否为空 */
|
||||
val isEmpty = stack.isEmpty()
|
||||
```
|
||||
@ -335,7 +335,28 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="stack.rb"
|
||||
# 初始化栈
|
||||
# Ruby 没有内置的栈类,可以把 Array 当作栈来使用
|
||||
stack = []
|
||||
|
||||
# 元素入栈
|
||||
stack << 1
|
||||
stack << 3
|
||||
stack << 2
|
||||
stack << 5
|
||||
stack << 4
|
||||
|
||||
# 访问栈顶元素
|
||||
peek = stack.last
|
||||
|
||||
# 元素出栈
|
||||
pop = stack.pop
|
||||
|
||||
# 获取栈的长度
|
||||
size = stack.length
|
||||
|
||||
# 判断是否为空
|
||||
is_empty = stack.empty?
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1078,7 +1099,7 @@ comments: true
|
||||
/* 访问栈顶元素 */
|
||||
fun peek(): Int? {
|
||||
if (isEmpty()) throw IndexOutOfBoundsException()
|
||||
return stackPeek?.value
|
||||
return stackPeek?._val
|
||||
}
|
||||
|
||||
/* 将 List 转化为 Array 并返回 */
|
||||
@ -1086,7 +1107,7 @@ comments: true
|
||||
var node = stackPeek
|
||||
val res = IntArray(size())
|
||||
for (i in res.size - 1 downTo 0) {
|
||||
res[i] = node?.value!!
|
||||
res[i] = node?._val!!
|
||||
node = node.next
|
||||
}
|
||||
return res
|
||||
@ -1097,7 +1118,54 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="linkedlist_stack.rb"
|
||||
[class]{LinkedListStack}-[func]{}
|
||||
### 基于链表实现的栈 ###
|
||||
class LinkedListStack
|
||||
attr_reader :size
|
||||
|
||||
### 构造方法 ###
|
||||
def initialize
|
||||
@size = 0
|
||||
end
|
||||
|
||||
### 判断栈是否为空 ###
|
||||
def is_empty?
|
||||
@peek.nil?
|
||||
end
|
||||
|
||||
### 入栈 ###
|
||||
def push(val)
|
||||
node = ListNode.new(val)
|
||||
node.next = @peek
|
||||
@peek = node
|
||||
@size += 1
|
||||
end
|
||||
|
||||
### 出栈 ###
|
||||
def pop
|
||||
num = peek
|
||||
@peek = @peek.next
|
||||
@size -= 1
|
||||
num
|
||||
end
|
||||
|
||||
### 访问栈顶元素 ###
|
||||
def peek
|
||||
raise IndexError, '栈为空' if is_empty?
|
||||
|
||||
@peek.val
|
||||
end
|
||||
|
||||
### 将链表转化为 Array 并反回 ###
|
||||
def to_array
|
||||
arr = []
|
||||
node = @peek
|
||||
while node
|
||||
arr << node.val
|
||||
node = node.next
|
||||
end
|
||||
arr.reverse
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@ -1738,7 +1806,7 @@ comments: true
|
||||
/* 基于数组实现的栈 */
|
||||
class ArrayStack {
|
||||
// 初始化列表(动态数组)
|
||||
private val stack = ArrayList<Int>()
|
||||
private val stack = mutableListOf<Int>()
|
||||
|
||||
/* 获取栈的长度 */
|
||||
fun size(): Int {
|
||||
@ -1769,7 +1837,7 @@ comments: true
|
||||
|
||||
/* 将 List 转化为 Array 并返回 */
|
||||
fun toArray(): Array<Any> {
|
||||
return stack.toArray()
|
||||
return stack.toTypedArray()
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1777,7 +1845,47 @@ comments: true
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="array_stack.rb"
|
||||
[class]{ArrayStack}-[func]{}
|
||||
### 基于数组实现的栈 ###
|
||||
class ArrayStack
|
||||
### 构造方法 ###
|
||||
def initialize
|
||||
@stack = []
|
||||
end
|
||||
|
||||
### 获取栈的长度 ###
|
||||
def size
|
||||
@stack.length
|
||||
end
|
||||
|
||||
### 判断栈是否为空 ###
|
||||
def is_empty?
|
||||
@stack.empty?
|
||||
end
|
||||
|
||||
### 入栈 ###
|
||||
def push(item)
|
||||
@stack << item
|
||||
end
|
||||
|
||||
### 出栈 ###
|
||||
def pop
|
||||
raise IndexError, '栈为空' if is_empty?
|
||||
|
||||
@stack.pop
|
||||
end
|
||||
|
||||
### 访问栈顶元素 ###
|
||||
def peek
|
||||
raise IndexError, '栈为空' if is_empty?
|
||||
|
||||
@stack.last
|
||||
end
|
||||
|
||||
### 返回列表用于打印 ###
|
||||
def to_array
|
||||
@stack
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
@ -1172,8 +1172,8 @@ comments: true
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title="array_binary_tree.kt"
|
||||
/* 数组表示下的二叉树类 */
|
||||
class ArrayBinaryTree(val tree: List<Int?>) {
|
||||
/* 构造方法 */
|
||||
class ArrayBinaryTree(val tree: MutableList<Int?>) {
|
||||
/* 列表容量 */
|
||||
fun size(): Int {
|
||||
return tree.size
|
||||
@ -1202,11 +1202,12 @@ comments: true
|
||||
}
|
||||
|
||||
/* 层序遍历 */
|
||||
fun levelOrder(): List<Int?> {
|
||||
val res = ArrayList<Int?>()
|
||||
fun levelOrder(): MutableList<Int?> {
|
||||
val res = mutableListOf<Int?>()
|
||||
// 直接遍历数组
|
||||
for (i in 0..<size()) {
|
||||
if (value(i) != null) res.add(value(i))
|
||||
if (value(i) != null)
|
||||
res.add(value(i))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -1214,34 +1215,38 @@ comments: true
|
||||
/* 深度优先遍历 */
|
||||
fun dfs(i: Int, order: String, res: MutableList<Int?>) {
|
||||
// 若为空位,则返回
|
||||
if (value(i) == null) return
|
||||
if (value(i) == null)
|
||||
return
|
||||
// 前序遍历
|
||||
if ("pre" == order) res.add(value(i))
|
||||
if ("pre" == order)
|
||||
res.add(value(i))
|
||||
dfs(left(i), order, res)
|
||||
// 中序遍历
|
||||
if ("in" == order) res.add(value(i))
|
||||
if ("in" == order)
|
||||
res.add(value(i))
|
||||
dfs(right(i), order, res)
|
||||
// 后序遍历
|
||||
if ("post" == order) res.add(value(i))
|
||||
if ("post" == order)
|
||||
res.add(value(i))
|
||||
}
|
||||
|
||||
/* 前序遍历 */
|
||||
fun preOrder(): List<Int?> {
|
||||
val res = ArrayList<Int?>()
|
||||
fun preOrder(): MutableList<Int?> {
|
||||
val res = mutableListOf<Int?>()
|
||||
dfs(0, "pre", res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* 中序遍历 */
|
||||
fun inOrder(): List<Int?> {
|
||||
val res = ArrayList<Int?>()
|
||||
fun inOrder(): MutableList<Int?> {
|
||||
val res = mutableListOf<Int?>()
|
||||
dfs(0, "in", res)
|
||||
return res
|
||||
}
|
||||
|
||||
/* 后序遍历 */
|
||||
fun postOrder(): List<Int?> {
|
||||
val res = ArrayList<Int?>()
|
||||
fun postOrder(): MutableList<Int?> {
|
||||
val res = mutableListOf<Int?>()
|
||||
dfs(0, "post", res)
|
||||
return res
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二
|
||||
/* 更新节点高度 */
|
||||
fun updateHeight(node: TreeNode?) {
|
||||
// 节点高度等于最高子树高度 + 1
|
||||
node?.height = (max(height(node?.left).toDouble(), height(node?.right).toDouble()) + 1).toInt()
|
||||
node?.height = max(height(node?.left), height(node?.right)) + 1
|
||||
}
|
||||
```
|
||||
|
||||
@ -2022,10 +2022,12 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区
|
||||
return TreeNode(value)
|
||||
var node = n
|
||||
/* 1. 查找插入位置并插入节点 */
|
||||
if (value < node.value) node.left = insertHelper(node.left, value)
|
||||
else if (value > node.value) node.right = insertHelper(node.right, value)
|
||||
else return node // 重复节点不插入,直接返回
|
||||
|
||||
if (value < node.value)
|
||||
node.left = insertHelper(node.left, value)
|
||||
else if (value > node.value)
|
||||
node.right = insertHelper(node.right, value)
|
||||
else
|
||||
return node // 重复节点不插入,直接返回
|
||||
updateHeight(node) // 更新节点高度
|
||||
/* 2. 执行旋转操作,使该子树重新恢复平衡 */
|
||||
node = rotate(node)
|
||||
@ -2601,14 +2603,22 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区
|
||||
fun removeHelper(n: TreeNode?, value: Int): TreeNode? {
|
||||
var node = n ?: return null
|
||||
/* 1. 查找节点并删除 */
|
||||
if (value < node.value) node.left = removeHelper(node.left, value)
|
||||
else if (value > node.value) node.right = removeHelper(node.right, value)
|
||||
if (value < node.value)
|
||||
node.left = removeHelper(node.left, value)
|
||||
else if (value > node.value)
|
||||
node.right = removeHelper(node.right, value)
|
||||
else {
|
||||
if (node.left == null || node.right == null) {
|
||||
val child = if (node.left != null) node.left else node.right
|
||||
val child = if (node.left != null)
|
||||
node.left
|
||||
else
|
||||
node.right
|
||||
// 子节点数量 = 0 ,直接删除 node 并返回
|
||||
if (child == null) return null
|
||||
else node = child
|
||||
if (child == null)
|
||||
return null
|
||||
// 子节点数量 = 1 ,直接删除 node
|
||||
else
|
||||
node = child
|
||||
} else {
|
||||
// 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点
|
||||
var temp = node.right
|
||||
|
@ -299,11 +299,14 @@ comments: true
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while (cur != null) {
|
||||
// 目标节点在 cur 的右子树中
|
||||
cur = if (cur.value < num) cur.right
|
||||
cur = if (cur.value < num)
|
||||
cur.right
|
||||
// 目标节点在 cur 的左子树中
|
||||
else if (cur.value > num) cur.left
|
||||
else if (cur.value > num)
|
||||
cur.left
|
||||
// 找到目标节点,跳出循环
|
||||
else break
|
||||
else
|
||||
break
|
||||
}
|
||||
// 返回目标节点
|
||||
return cur
|
||||
@ -748,17 +751,22 @@ comments: true
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while (cur != null) {
|
||||
// 找到重复节点,直接返回
|
||||
if (cur.value == num) return
|
||||
if (cur.value == num)
|
||||
return
|
||||
pre = cur
|
||||
// 插入位置在 cur 的右子树中
|
||||
cur = if (cur.value < num) cur.right
|
||||
cur = if (cur.value < num)
|
||||
cur.right
|
||||
// 插入位置在 cur 的左子树中
|
||||
else cur.left
|
||||
else
|
||||
cur.left
|
||||
}
|
||||
// 插入节点
|
||||
val node = TreeNode(num)
|
||||
if (pre?.value!! < num) pre.right = node
|
||||
else pre.left = node
|
||||
if (pre?.value!! < num)
|
||||
pre.right = node
|
||||
else
|
||||
pre.left = node
|
||||
}
|
||||
```
|
||||
|
||||
@ -1482,29 +1490,39 @@ comments: true
|
||||
/* 删除节点 */
|
||||
fun remove(num: Int) {
|
||||
// 若树为空,直接提前返回
|
||||
if (root == null) return
|
||||
if (root == null)
|
||||
return
|
||||
var cur = root
|
||||
var pre: TreeNode? = null
|
||||
// 循环查找,越过叶节点后跳出
|
||||
while (cur != null) {
|
||||
// 找到待删除节点,跳出循环
|
||||
if (cur.value == num) break
|
||||
if (cur.value == num)
|
||||
break
|
||||
pre = cur
|
||||
// 待删除节点在 cur 的右子树中
|
||||
cur = if (cur.value < num) cur.right
|
||||
cur = if (cur.value < num)
|
||||
cur.right
|
||||
// 待删除节点在 cur 的左子树中
|
||||
else cur.left
|
||||
else
|
||||
cur.left
|
||||
}
|
||||
// 若无待删除节点,则直接返回
|
||||
if (cur == null) return
|
||||
if (cur == null)
|
||||
return
|
||||
// 子节点数量 = 0 or 1
|
||||
if (cur.left == null || cur.right == null) {
|
||||
// 当子节点数量 = 0 / 1 时, child = null / 该子节点
|
||||
val child = if (cur.left != null) cur.left else cur.right
|
||||
val child = if (cur.left != null)
|
||||
cur.left
|
||||
else
|
||||
cur.right
|
||||
// 删除节点 cur
|
||||
if (cur != root) {
|
||||
if (pre!!.left == cur) pre.left = child
|
||||
else pre.right = child
|
||||
if (pre!!.left == cur)
|
||||
pre.left = child
|
||||
else
|
||||
pre.right = child
|
||||
} else {
|
||||
// 若删除节点为根节点,则重新指定根节点
|
||||
root = child
|
||||
|
@ -229,7 +229,7 @@ comments: true
|
||||
fn level_order(root: &Rc<RefCell<TreeNode>>) -> Vec<i32> {
|
||||
// 初始化队列,加入根节点
|
||||
let mut que = VecDeque::new();
|
||||
que.push_back(Rc::clone(&root));
|
||||
que.push_back(root.clone());
|
||||
// 初始化一个列表,用于保存遍历序列
|
||||
let mut vec = Vec::new();
|
||||
|
||||
@ -237,10 +237,10 @@ comments: true
|
||||
// 队列出队
|
||||
vec.push(node.borrow().val); // 保存节点值
|
||||
if let Some(left) = node.borrow().left.as_ref() {
|
||||
que.push_back(Rc::clone(left)); // 左子节点入队
|
||||
que.push_back(left.clone()); // 左子节点入队
|
||||
}
|
||||
if let Some(right) = node.borrow().right.as_ref() {
|
||||
que.push_back(Rc::clone(right)); // 右子节点入队
|
||||
que.push_back(right.clone()); // 右子节点入队
|
||||
};
|
||||
}
|
||||
vec
|
||||
@ -302,13 +302,14 @@ comments: true
|
||||
val queue = LinkedList<TreeNode?>()
|
||||
queue.add(root)
|
||||
// 初始化一个列表,用于保存遍历序列
|
||||
val list = ArrayList<Int>()
|
||||
while (!queue.isEmpty()) {
|
||||
val node = queue.poll() // 队列出队
|
||||
list.add(node?.value!!) // 保存节点值
|
||||
if (node.left != null) queue.offer(node.left) // 左子节点入队
|
||||
|
||||
if (node.right != null) queue.offer(node.right) // 右子节点入队
|
||||
val list = mutableListOf<Int>()
|
||||
while (queue.isNotEmpty()) {
|
||||
val node = queue.poll() // 队列出队
|
||||
list.add(node?.value!!) // 保存节点值
|
||||
if (node.left != null)
|
||||
queue.offer(node.left) // 左子节点入队
|
||||
if (node.right != null)
|
||||
queue.offer(node.right) // 右子节点入队
|
||||
}
|
||||
return list
|
||||
}
|
||||
@ -689,8 +690,8 @@ comments: true
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:根节点 -> 左子树 -> 右子树
|
||||
result.push(node.borrow().val);
|
||||
result.append(&mut pre_order(node.borrow().left.as_ref()));
|
||||
result.append(&mut pre_order(node.borrow().right.as_ref()));
|
||||
result.extend(pre_order(node.borrow().left.as_ref()));
|
||||
result.extend(pre_order(node.borrow().right.as_ref()));
|
||||
}
|
||||
result
|
||||
}
|
||||
@ -701,9 +702,9 @@ comments: true
|
||||
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:左子树 -> 根节点 -> 右子树
|
||||
result.append(&mut in_order(node.borrow().left.as_ref()));
|
||||
result.extend(in_order(node.borrow().left.as_ref()));
|
||||
result.push(node.borrow().val);
|
||||
result.append(&mut in_order(node.borrow().right.as_ref()));
|
||||
result.extend(in_order(node.borrow().right.as_ref()));
|
||||
}
|
||||
result
|
||||
}
|
||||
@ -714,8 +715,8 @@ comments: true
|
||||
|
||||
if let Some(node) = root {
|
||||
// 访问优先级:左子树 -> 右子树 -> 根节点
|
||||
result.append(&mut post_order(node.borrow().left.as_ref()));
|
||||
result.append(&mut post_order(node.borrow().right.as_ref()));
|
||||
result.extend(post_order(node.borrow().left.as_ref()));
|
||||
result.extend(post_order(node.borrow().right.as_ref()));
|
||||
result.push(node.borrow().val);
|
||||
}
|
||||
result
|
||||
|
@ -111,20 +111,22 @@
|
||||
<!-- Section: brief introduction -->
|
||||
<section data-md-color-scheme="slate" class="home-div">
|
||||
<div class="section-content">
|
||||
<img src="index.assets/hello_algo_header.png" style="width: 100%; max-width: 39em;" alt="Preview">
|
||||
<img src="index.assets/hello_algo_header.png" style="width: 100%; max-width: 41.5em;" alt="Preview">
|
||||
<div class="code-badge">
|
||||
<img src="https://img.shields.io/badge/Python-snow?logo=python&logoColor=3776AB" alt="">
|
||||
<img src="https://img.shields.io/badge/C%2B%2B-snow?logo=c%2B%2B&logoColor=00599C" alt="">
|
||||
<img src="https://img.shields.io/badge/Java-snow?logo=coffeescript&logoColor=FC4C02" alt="">
|
||||
<img src="https://img.shields.io/badge/C%23-snow?logo=csharp&logoColor=512BD4" alt="">
|
||||
<img src="https://img.shields.io/badge/Go-snow?logo=go&logoColor=00ADD8" alt="">
|
||||
<img src="https://img.shields.io/badge/Swift-snow?logo=swift&logoColor=F05138" alt="">
|
||||
<img src="https://img.shields.io/badge/JavaScript-snow?logo=javascript&logoColor=E9CE30" alt="">
|
||||
<img src="https://img.shields.io/badge/TypeScript-snow?logo=typescript&logoColor=3178C6" alt="">
|
||||
<img src="https://img.shields.io/badge/Dart-snow?logo=dart&logoColor=0175C2" alt="">
|
||||
<img src="https://img.shields.io/badge/Rust-snow?logo=rust&logoColor=000000" alt="">
|
||||
<img src="https://img.shields.io/badge/C-snow?logo=c&logoColor=A8B9CC" alt="">
|
||||
<img src="https://img.shields.io/badge/Zig-snow?logo=zig&logoColor=F7A41D" alt="">
|
||||
<img src="https://img.shields.io/badge/Python-snow?logo=python&logoColor=3776AB" alt="" />
|
||||
<img src="https://img.shields.io/badge/Java-snow?logo=coffeescript&logoColor=FC4C02" alt="" />
|
||||
<img src="https://img.shields.io/badge/C%2B%2B-snow?logo=c%2B%2B&logoColor=00599C" alt="" />
|
||||
<img src="https://img.shields.io/badge/C-snow?logo=c&logoColor=A8B9CC" alt="" />
|
||||
<img src="https://img.shields.io/badge/C%23-snow?logo=csharp&logoColor=512BD4" alt="" />
|
||||
<img src="https://img.shields.io/badge/JS-snow?logo=javascript&logoColor=E9CE30" alt="" />
|
||||
<img src="https://img.shields.io/badge/Go-snow?logo=go&logoColor=00ADD8" alt="" />
|
||||
<img src="https://img.shields.io/badge/Swift-snow?logo=swift&logoColor=F05138" alt="" />
|
||||
<img src="https://img.shields.io/badge/Rust-snow?logo=rust&logoColor=000000" alt="" />
|
||||
<img src="https://img.shields.io/badge/Ruby-snow?logo=ruby&logoColor=CC342D" alt="" />
|
||||
<img src="https://img.shields.io/badge/Kotlin-snow?logo=kotlin&logoColor=7F52FF" alt="" />
|
||||
<img src="https://img.shields.io/badge/TS-snow?logo=typescript&logoColor=3178C6" alt="" />
|
||||
<img src="https://img.shields.io/badge/Dart-snow?logo=dart&logoColor=0175C2" alt="" />
|
||||
<img src="https://img.shields.io/badge/Zig-snow?logo=zig&logoColor=F7A41D" alt="" />
|
||||
</div>
|
||||
<p style="margin-top: 2em;">500 幅动画图解、12 种编程语言代码、3000 条社区问答,助你快速入门数据结构与算法</p>
|
||||
</div>
|
||||
@ -284,6 +286,14 @@
|
||||
<br><sub>Zig, Rust</sub>
|
||||
</a>
|
||||
</div>
|
||||
<div class="profile-cell">
|
||||
<a href="https://github.com/curtishd">
|
||||
<img class="profile-img" src="assets/avatar/avatar_curtishd.jpg"
|
||||
alt="Reviewer: curtishd" />
|
||||
<br><b>curtishd</b>
|
||||
<br><sub>Kotlin</sub>
|
||||
</a>
|
||||
</div>
|
||||
<div class="profile-cell">
|
||||
<a href="https://github.com/Gonglja">
|
||||
<img class="profile-img" src="assets/avatar/avatar_Gonglja.jpg" alt="Reviewer: Gonglja" />
|
||||
@ -347,7 +357,7 @@
|
||||
<!-- contributors -->
|
||||
<div style="margin: 2em auto;">
|
||||
<h3>贡献者</h3>
|
||||
<p>本书在开源社区 140 多位贡献者的共同努力下不断完善,感谢他们付出的时间与精力!</p>
|
||||
<p>本书在开源社区一百多位贡献者的共同努力下不断完善,感谢他们付出的时间与精力!</p>
|
||||
<a href="https://github.com/krahets/hello-algo/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=krahets/hello-algo&max=300&columns=16" alt="Contributors"
|
||||
style="width: 100%; max-width: 38.5em;">
|
||||
|
Reference in New Issue
Block a user