diff --git a/docs/chapter_appendix/terminology.md b/docs/chapter_appendix/terminology.md
index 125b9e9c8..e684a026c 100644
--- a/docs/chapter_appendix/terminology.md
+++ b/docs/chapter_appendix/terminology.md
@@ -136,7 +136,7 @@ comments: true
| $n$-queens problem | $n$ 皇后问题 | $n$ 皇后問題 |
| dynamic programming | 动态规划 | 動態規劃 |
| initial state | 初始状态 | 初始狀態 |
-| state-trasition equation | 状态转移方程 | 狀態轉移方程 |
+| state-transition equation | 状态转移方程 | 狀態轉移方程 |
| knapsack problem | 背包问题 | 背包問題 |
| edit distance problem | 编辑距离问题 | 編輯距離問題 |
| greedy algorithm | 贪心算法 | 貪婪演算法 |
diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md
index 847ee1fd9..2c110d915 100755
--- a/docs/chapter_array_and_linkedlist/array.md
+++ b/docs/chapter_array_and_linkedlist/array.md
@@ -111,6 +111,12 @@ comments: true
int nums[5] = { 1, 3, 2, 5, 4 };
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -279,6 +285,19 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 随机访问元素 */
+ fun randomAccess(nums: IntArray): Int {
+ // 在区间 [0, nums.size) 中随机抽取一个数字
+ val randomIndex = ThreadLocalRandom.current().nextInt(0, nums.size)
+ // 获取并返回随机元素
+ val randomNum = nums[randomIndex]
+ return randomNum
+ }
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -459,6 +478,20 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 在数组的索引 index 处插入元素 num */
+ fun insert(nums: IntArray, num: Int, index: Int) {
+ // 把索引 index 以及之后的所有元素向后移动一位
+ for (i in nums.size - 1 downTo index + 1) {
+ nums[i] = nums[i - 1]
+ }
+ // 将 num 赋给 index 处的元素
+ nums[index] = num
+ }
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -620,6 +653,18 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 删除索引 index 处的元素 */
+ fun remove(nums: IntArray, index: Int) {
+ // 把索引 index 之后的所有元素向前移动一位
+ for (i in index..next = n4;
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -534,6 +546,17 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 在链表的节点 n0 之后插入节点p */
+ fun insert(n0: ListNode?, p: ListNode?) {
+ val n1 = n0?.next
+ p?.next = n1
+ n0?.next = p
+ }
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -723,6 +746,17 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 删除链表的节点 n0 之后的首个节点 */
+ fun remove(n0: ListNode?) {
+ val p = n0?.next
+ val n1 = p?.next
+ n0?.next = n1
+ }
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -903,6 +937,19 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 访问链表中索引为 index 的节点 */
+ fun access(head: ListNode?, index: Int): ListNode? {
+ var h = head
+ for (i in 0..= size)
+ throw IndexOutOfBoundsException()
+ return arr[index]
+ }
+
+ /* 更新元素 */
+ fun set(index: Int, num: Int) {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ arr[index] = num
+ }
+
+ /* 在尾部添加元素 */
+ fun add(num: Int) {
+ // 元素数量超出容量时,触发扩容机制
+ if (size == capacity())
+ extendCapacity()
+ arr[size] = num
+ // 更新元素数量
+ size++
+ }
+
+ /* 在中间插入元素 */
+ fun insert(index: Int, num: Int) {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ // 元素数量超出容量时,触发扩容机制
+ if (size == capacity())
+ extendCapacity()
+ // 将索引 index 以及之后的元素都向后移动一位
+ for (j in size - 1 downTo index)
+ arr[j + 1] = arr[j]
+ arr[index] = num
+ // 更新元素数量
+ size++
+ }
+
+ /* 删除元素 */
+ fun remove(index: Int): Int {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ val num: Int = arr[index]
+ // 将将索引 index 之后的元素都向前移动一位
+ for (j in index..): Boolean {
+ return state.isNotEmpty() && state[state.size - 1]?.value == 7
+ }
+
+ /* 记录解 */
+ fun recordSolution(state: MutableList?, res: MutableList?>) {
+ res.add(state?.let { ArrayList(it) })
+ }
+
+ /* 判断在当前状态下,该选择是否合法 */
+ fun isValid(state: List?, choice: TreeNode?): Boolean {
+ return choice != null && choice.value != 3
+ }
+
+ /* 更新状态 */
+ fun makeChoice(state: MutableList, choice: TreeNode?) {
+ state.add(choice)
+ }
+
+ /* 恢复状态 */
+ fun undoChoice(state: MutableList, choice: TreeNode?) {
+ state.removeLast()
+ }
+
+ /* 回溯算法:例题三 */
+ fun backtrack(
+ state: MutableList,
+ choices: List,
+ res: MutableList?>
+ ) {
+ // 检查是否为解
+ if (isSolution(state)) {
+ // 记录解
+ recordSolution(state, res)
+ }
+ // 遍历所有选择
+ for (choice in choices) {
+ // 剪枝:检查选择是否合法
+ if (isValid(state, choice)) {
+ // 尝试:做出选择,更新状态
+ makeChoice(state, choice)
+ // 进行下一轮选择
+ backtrack(state, listOf(choice!!.left, choice.right), res)
+ // 回退:撤销选择,恢复到之前的状态
+ undoChoice(state, choice)
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="preorder_traversal_iii_template.zig"
diff --git a/docs/chapter_backtracking/n_queens_problem.md b/docs/chapter_backtracking/n_queens_problem.md
index c2efa6cbf..646771d24 100644
--- a/docs/chapter_backtracking/n_queens_problem.md
+++ b/docs/chapter_backtracking/n_queens_problem.md
@@ -639,6 +639,73 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="n_queens.kt"
+ /* 回溯算法:n 皇后 */
+ fun backtrack(
+ row: Int,
+ n: Int,
+ state: List>,
+ res: MutableList>?>,
+ cols: BooleanArray,
+ diags1: BooleanArray,
+ diags2: BooleanArray
+ ) {
+ // 当放置完所有行时,记录解
+ if (row == n) {
+ val copyState: MutableList> = ArrayList()
+ for (sRow in state) {
+ copyState.add(ArrayList(sRow))
+ }
+ res.add(copyState)
+ return
+ }
+ // 遍历所有列
+ for (col in 0..>?> {
+ // 初始化 n*n 大小的棋盘,其中 'Q' 代表皇后,'#' 代表空位
+ val state: MutableList> = ArrayList()
+ for (i in 0.. = ArrayList()
+ for (j in 0..>?> = ArrayList()
+
+ backtrack(0, n, state, res, cols, diags1, diags2)
+
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="n_queens.zig"
diff --git a/docs/chapter_backtracking/permutations_problem.md b/docs/chapter_backtracking/permutations_problem.md
index 950196f76..e29edd4a6 100644
--- a/docs/chapter_backtracking/permutations_problem.md
+++ b/docs/chapter_backtracking/permutations_problem.md
@@ -463,6 +463,46 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="permutations_i.kt"
+ /* 回溯算法:全排列 I */
+ fun backtrack(
+ state: MutableList,
+ choices: IntArray,
+ selected: BooleanArray,
+ res: MutableList?>
+ ) {
+ // 当状态长度等于元素数量时,记录解
+ if (state.size == choices.size) {
+ res.add(ArrayList(state))
+ return
+ }
+ // 遍历所有选择
+ for (i in choices.indices) {
+ val choice = choices[i]
+ // 剪枝:不允许重复选择元素
+ if (!selected[i]) {
+ // 尝试:做出选择,更新状态
+ selected[i] = true
+ state.add(choice)
+ // 进行下一轮选择
+ backtrack(state, choices, selected, res)
+ // 回退:撤销选择,恢复到之前的状态
+ selected[i] = false
+ state.removeAt(state.size - 1)
+ }
+ }
+ }
+
+ /* 全排列 I */
+ fun permutationsI(nums: IntArray): List?> {
+ val res: MutableList?> = ArrayList()
+ backtrack(ArrayList(), nums, BooleanArray(nums.size), res)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="permutations_i.zig"
@@ -939,6 +979,48 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="permutations_ii.kt"
+ /* 回溯算法:全排列 II */
+ fun backtrack(
+ state: MutableList,
+ choices: IntArray,
+ selected: BooleanArray,
+ res: MutableList?>
+ ) {
+ // 当状态长度等于元素数量时,记录解
+ if (state.size == choices.size) {
+ res.add(ArrayList(state))
+ return
+ }
+ // 遍历所有选择
+ val duplicated: MutableSet = HashSet()
+ for (i in choices.indices) {
+ val choice = choices[i]
+ // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素
+ if (!selected[i] && !duplicated.contains(choice)) {
+ // 尝试:做出选择,更新状态
+ duplicated.add(choice) // 记录选择过的元素值
+ selected[i] = true
+ state.add(choice)
+ // 进行下一轮选择
+ backtrack(state, choices, selected, res)
+ // 回退:撤销选择,恢复到之前的状态
+ selected[i] = false
+ state.removeAt(state.size - 1)
+ }
+ }
+ }
+
+ /* 全排列 II */
+ fun permutationsII(nums: IntArray): MutableList?> {
+ val res: MutableList?> = ArrayList()
+ backtrack(ArrayList(), nums, BooleanArray(nums.size), res)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="permutations_ii.zig"
diff --git a/docs/chapter_backtracking/subset_sum_problem.md b/docs/chapter_backtracking/subset_sum_problem.md
index 5512b96db..386718046 100644
--- a/docs/chapter_backtracking/subset_sum_problem.md
+++ b/docs/chapter_backtracking/subset_sum_problem.md
@@ -426,6 +426,47 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="subset_sum_i_naive.kt"
+ /* 回溯算法:子集和 I */
+ fun backtrack(
+ state: MutableList,
+ target: Int,
+ total: Int,
+ choices: IntArray,
+ res: MutableList?>
+ ) {
+ // 子集和等于 target 时,记录解
+ if (total == target) {
+ res.add(ArrayList(state))
+ return
+ }
+ // 遍历所有选择
+ for (i in choices.indices) {
+ // 剪枝:若子集和超过 target ,则跳过该选择
+ if (total + choices[i] > target) {
+ continue
+ }
+ // 尝试:做出选择,更新元素和 total
+ state.add(choices[i])
+ // 进行下一轮选择
+ backtrack(state, target, total + choices[i], choices, res)
+ // 回退:撤销选择,恢复到之前的状态
+ state.removeAt(state.size - 1)
+ }
+ }
+
+ /* 求解子集和 I(包含重复子集) */
+ fun subsetSumINaive(nums: IntArray, target: Int): List?> {
+ val state: MutableList = ArrayList() // 状态(子集)
+ val total = 0 // 子集和
+ val res: MutableList?> = ArrayList() // 结果列表(子集列表)
+ backtrack(state, target, total, nums, res)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="subset_sum_i_naive.zig"
@@ -915,6 +956,50 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="subset_sum_i.kt"
+ /* 回溯算法:子集和 I */
+ fun backtrack(
+ state: MutableList,
+ target: Int,
+ choices: IntArray,
+ start: Int,
+ res: MutableList?>
+ ) {
+ // 子集和等于 target 时,记录解
+ if (target == 0) {
+ res.add(ArrayList(state))
+ return
+ }
+ // 遍历所有选择
+ // 剪枝二:从 start 开始遍历,避免生成重复子集
+ for (i in start..?> {
+ val state: MutableList = ArrayList() // 状态(子集)
+ Arrays.sort(nums) // 对 nums 进行排序
+ val start = 0 // 遍历起始点
+ val res: MutableList?> = ArrayList() // 结果列表(子集列表)
+ backtrack(state, target, nums, start, res)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="subset_sum_i.zig"
@@ -1445,6 +1530,55 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="subset_sum_ii.kt"
+ /* 回溯算法:子集和 II */
+ fun backtrack(
+ state: MutableList,
+ target: Int,
+ choices: IntArray,
+ start: Int,
+ res: MutableList?>
+ ) {
+ // 子集和等于 target 时,记录解
+ if (target == 0) {
+ res.add(ArrayList(state))
+ return
+ }
+ // 遍历所有选择
+ // 剪枝二:从 start 开始遍历,避免生成重复子集
+ // 剪枝三:从 start 开始遍历,避免重复选择同一元素
+ for (i in start.. start && choices[i] == choices[i - 1]) {
+ continue
+ }
+ // 尝试:做出选择,更新 target, start
+ state.add(choices[i])
+ // 进行下一轮选择
+ backtrack(state, target - choices[i], choices, i + 1, res)
+ // 回退:撤销选择,恢复到之前的状态
+ state.removeAt(state.size - 1)
+ }
+ }
+
+ /* 求解子集和 II */
+ fun subsetSumII(nums: IntArray, target: Int): List?> {
+ val state: MutableList = ArrayList() // 状态(子集)
+ Arrays.sort(nums) // 对 nums 进行排序
+ val start = 0 // 遍历起始点
+ val res: MutableList?> = ArrayList() // 结果列表(子集列表)
+ backtrack(state, target, nums, start, res)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="subset_sum_ii.zig"
diff --git a/docs/chapter_computational_complexity/iteration_and_recursion.md b/docs/chapter_computational_complexity/iteration_and_recursion.md
index 7bf08dc5e..8cc8be30a 100644
--- a/docs/chapter_computational_complexity/iteration_and_recursion.md
+++ b/docs/chapter_computational_complexity/iteration_and_recursion.md
@@ -168,6 +168,20 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="iteration.kt"
+ /* for 循环 */
+ fun forLoop(n: Int): Int {
+ var res = 0
+ // 循环求和 1, 2, ..., n-1, n
+ for (i in 1..n) {
+ res += i
+ }
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="iteration.zig"
@@ -378,6 +392,22 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="iteration.kt"
+ /* while 循环 */
+ fun whileLoop(n: Int): Int {
+ var res = 0
+ var i = 1 // 初始化条件变量
+ // 循环求和 1, 2, ..., n-1, n
+ while (i <= n) {
+ res += i
+ i++ // 更新条件变量
+ }
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="iteration.zig"
@@ -601,6 +631,24 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="iteration.kt"
+ /* while 循环(两次更新) */
+ fun whileLoopII(n: Int): Int {
+ var res = 0
+ var i = 1 // 初始化条件变量
+ // 循环求和 1, 4, 10, ...
+ while (i <= n) {
+ res += i
+ // 更新条件变量
+ i++
+ i *= 2
+ }
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="iteration.zig"
@@ -818,6 +866,23 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="iteration.kt"
+ /* 双层 for 循环 */
+ fun nestedForLoop(n: Int): String {
+ val res = StringBuilder()
+ // 循环 i = 1, 2, ..., n-1, n
+ for (i in 1..n) {
+ // 循环 j = 1, 2, ..., n-1, n
+ for (j in 1..n) {
+ res.append(" ($i, $j), ")
+ }
+ }
+ return res.toString()
+ }
+ ```
+
=== "Zig"
```zig title="iteration.zig"
@@ -1032,6 +1097,21 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="recursion.kt"
+ /* 递归 */
+ fun recur(n: Int): Int {
+ // 终止条件
+ if (n == 1)
+ return 1
+ // 递: 递归调用
+ val res = recur(n - 1)
+ // 归: 返回结果
+ return n + res
+ }
+ ```
+
=== "Zig"
```zig title="recursion.zig"
@@ -1235,6 +1315,19 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="recursion.kt"
+ /* Kotlin tailrec 关键词使函数实现尾递归优化 */
+ tailrec fun tailRecur(n: Int, res: Int): Int {
+ // 终止条件
+ if (n == 0)
+ return res
+ // 尾递归调用
+ return tailRecur(n - 1, res + n)
+ }
+ ```
+
=== "Zig"
```zig title="recursion.zig"
@@ -1446,6 +1539,21 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="recursion.kt"
+ /* 斐波那契数列:递归 */
+ fun fib(n: Int): Int {
+ // 终止条件 f(1) = 0, f(2) = 1
+ if (n == 1 || n == 2)
+ return n - 1
+ // 递归调用 f(n) = f(n-1) + f(n-2)
+ val res = fib(n - 1) + fib(n - 2)
+ // 返回结果 f(n)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="recursion.zig"
@@ -1760,6 +1868,28 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="recursion.kt"
+ /* 使用迭代模拟递归 */
+ fun forLoopRecur(n: Int): Int {
+ // 使用一个显式的栈来模拟系统调用栈
+ val stack = Stack()
+ var res = 0
+ // 递: 递归调用
+ for (i in n downTo 0) {
+ stack.push(i)
+ }
+ // 归: 返回结果
+ while (stack.isNotEmpty()) {
+ // 通过“出栈操作”模拟“归”
+ res += stack.pop()
+ }
+ // res = 1+2+3+...+n
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="recursion.zig"
diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md
index c2c47eac6..ba694ceb8 100755
--- a/docs/chapter_computational_complexity/space_complexity.md
+++ b/docs/chapter_computational_complexity/space_complexity.md
@@ -315,6 +315,12 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -461,6 +467,12 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -481,9 +493,10 @@ comments: true
for _ in range(n):
function()
- def recur(n: int) -> int:
+ def recur(n: int):
"""递归的空间复杂度为 O(n)"""
- if n == 1: return
+ if n == 1:
+ return
return recur(n - 1)
```
@@ -698,6 +711,12 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -724,7 +743,7 @@ $$
图 2-16 常见的空间复杂度类型
-### 1. 常数阶 $O(1)$
+### 1. 常数阶 $O(1)$ {data-toc-label="常数阶"}
常数阶常见于数量与输入数据大小 $n$ 无关的常量、变量、对象。
@@ -1030,6 +1049,33 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 函数 */
+ fun function(): Int {
+ // 执行某些操作
+ return 0
+ }
+
+ /* 常数阶 */
+ fun constant(n: Int) {
+ // 常量、变量、对象占用 O(1) 空间
+ val a = 0
+ var b = 0
+ val nums = Array(10000) { 0 }
+ val node = ListNode(0)
+ // 循环中的变量占用 O(1) 空间
+ for (i in 0..
-### 2. 线性阶 $O(n)$
+### 2. 线性阶 $O(n)$ {data-toc-label="线性阶"}
线性阶常见于元素数量与 $n$ 成正比的数组、链表、栈、队列等:
@@ -1306,6 +1352,26 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 线性阶 */
+ fun linear(n: Int) {
+ // 长度为 n 的数组占用 O(n) 空间
+ val nums = Array(n) { 0 }
+ // 长度为 n 的列表占用 O(n) 空间
+ val nodes = mutableListOf()
+ for (i in 0..()
+ for (i in 0.. 图 2-17 递归函数产生的线性阶空间复杂度
-### 3. 平方阶 $O(n^2)$
+### 3. 平方阶 $O(n^2)$ {data-toc-label="平方阶"}
平方阶常见于矩阵和图,元素数量与 $n$ 成平方关系:
@@ -1685,6 +1763,25 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 平方阶 */
+ fun quadratic(n: Int) {
+ // 矩阵占用 O(n^2) 空间
+ val numMatrix: Array?> = arrayOfNulls(n)
+ // 二维列表占用 O(n^2) 空间
+ val numList: MutableList> = arrayListOf()
+ for (i in 0..()
+ for (j in 0.. 图 2-18 递归函数产生的平方阶空间复杂度
-### 4. 指数阶 $O(2^n)$
+### 4. 指数阶 $O(2^n)$ {data-toc-label="指数阶"}
指数阶常见于二叉树。观察图 2-19 ,层数为 $n$ 的“满二叉树”的节点数量为 $2^n - 1$ ,占用 $O(2^n)$ 空间:
@@ -2038,6 +2149,20 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 指数阶(建立满二叉树) */
+ fun buildTree(n: Int): TreeNode? {
+ if (n == 0)
+ return null
+ val root = TreeNode(0)
+ root.left = buildTree(n - 1)
+ root.right = buildTree(n - 1)
+ return root
+ }
+ ```
+
=== "Zig"
```zig title="space_complexity.zig"
@@ -2061,7 +2186,7 @@ $$
图 2-19 满二叉树产生的指数阶空间复杂度
-### 5. 对数阶 $O(\log n)$
+### 5. 对数阶 $O(\log n)$ {data-toc-label="对数阶"}
对数阶常见于分治算法。例如归并排序,输入长度为 $n$ 的数组,每轮递归将数组从中点处划分为两半,形成高度为 $\log n$ 的递归树,使用 $O(\log n)$ 栈帧空间。
diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md
index b416344d1..ff73e2655 100755
--- a/docs/chapter_computational_complexity/time_complexity.md
+++ b/docs/chapter_computational_complexity/time_complexity.md
@@ -175,6 +175,12 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -433,6 +439,12 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -629,6 +641,12 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -888,6 +906,12 @@ $T(n)$ 是一次函数,说明其运行时间的增长趋势是线性的,因
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -954,7 +978,7 @@ $$
图 2-9 常见的时间复杂度类型
-### 1. 常数阶 $O(1)$
+### 1. 常数阶 $O(1)$ {data-toc-label="常数阶"}
常数阶的操作数量与输入数据大小 $n$ 无关,即不随着 $n$ 的变化而变化。
@@ -1107,6 +1131,19 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 常数阶 */
+ fun constant(n: Int): Int {
+ var count = 0
+ val size = 10_0000
+ for (i in 0..
-### 2. 线性阶 $O(n)$
+### 2. 线性阶 $O(n)$ {data-toc-label="线性阶"}
线性阶的操作数量相对于输入数据大小 $n$ 以线性级别增长。线性阶通常出现在单层循环中:
@@ -1266,6 +1303,19 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 线性阶 */
+ fun linear(n: Int): Int {
+ var count = 0
+ // 循环次数与数组长度成正比
+ for (i in 0.. nums[j + 1]) {
+ // 交换 nums[j] 与 nums[j + 1]
+ nums[j] = nums[j + 1].also { nums[j + 1] = nums[j] }
+ count += 3 // 元素交换包含 3 个单元操作
+ }
+ }
+ }
+ return count
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -1946,7 +2047,7 @@ $$
-### 4. 指数阶 $O(2^n)$
+### 4. 指数阶 $O(2^n)$ {data-toc-label="指数阶"}
生物学的“细胞分裂”是指数阶增长的典型例子:初始状态为 $1$ 个细胞,分裂一轮后变为 $2$ 个,分裂两轮后变为 $4$ 个,以此类推,分裂 $n$ 轮后有 $2^n$ 个细胞。
@@ -2153,6 +2254,25 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 指数阶(循环实现) */
+ fun exponential(n: Int): Int {
+ var count = 0
+ // 细胞每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
+ var base = 1
+ for (i in 0.. 1) {
+ n1 /= 2
+ count++
+ }
+ return count
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -2626,6 +2773,17 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 对数阶(递归实现) */
+ fun logRecur(n: Int): Int {
+ if (n <= 1)
+ return 0
+ return logRecur(n / 2) + 1
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -2653,7 +2811,7 @@ $$
也就是说,底数 $m$ 可以在不影响复杂度的前提下转换。因此我们通常会省略底数 $m$ ,将对数阶直接记为 $O(\log n)$ 。
-### 6. 线性对数阶 $O(n \log n)$
+### 6. 线性对数阶 $O(n \log n)$ {data-toc-label="线性对数阶"}
线性对数阶常出现于嵌套循环中,两层循环的时间复杂度分别为 $O(\log n)$ 和 $O(n)$ 。相关代码如下:
@@ -2819,6 +2977,21 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 线性对数阶 */
+ fun linearLogRecur(n: Int): Int {
+ if (n <= 1)
+ return 1
+ var count = linearLogRecur(n / 2) + linearLogRecur(n / 2)
+ for (i in 0.. {
+ val nums = IntArray(n)
+ // 生成数组 nums = { 1, 2, 3, ..., n }
+ for (i in 0.. int[]
+ val res = arrayOfNulls(n)
+ for (i in 0..): Int {
+ for (i in nums.indices) {
+ // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1)
+ // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n)
+ if (nums[i] == 1)
+ return i
+ }
+ return -1
+ }
+ ```
+
=== "Zig"
```zig title="worst_best_time_complexity.zig"
diff --git a/docs/chapter_data_structure/basic_data_types.md b/docs/chapter_data_structure/basic_data_types.md
index 16b4e7ba1..37d426228 100644
--- a/docs/chapter_data_structure/basic_data_types.md
+++ b/docs/chapter_data_structure/basic_data_types.md
@@ -161,6 +161,12 @@ comments: true
bool bools[10];
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
diff --git a/docs/chapter_divide_and_conquer/binary_search_recur.md b/docs/chapter_divide_and_conquer/binary_search_recur.md
index ed8c5f252..3fffe03bb 100644
--- a/docs/chapter_divide_and_conquer/binary_search_recur.md
+++ b/docs/chapter_divide_and_conquer/binary_search_recur.md
@@ -383,6 +383,42 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_recur.kt"
+ /* 二分查找:问题 f(i, j) */
+ fun dfs(
+ nums: IntArray,
+ target: Int,
+ i: Int,
+ j: Int
+ ): Int {
+ // 若区间为空,代表无目标元素,则返回 -1
+ if (i > j) {
+ return -1
+ }
+ // 计算中点索引 m
+ val m = (i + j) / 2
+ return if (nums[m] < target) {
+ // 递归子问题 f(m+1, j)
+ dfs(nums, target, m + 1, j)
+ } else if (nums[m] > target) {
+ // 递归子问题 f(i, m-1)
+ dfs(nums, target, i, m - 1)
+ } else {
+ // 找到目标元素,返回其索引
+ m
+ }
+ }
+
+ /* 二分查找 */
+ fun binarySearch(nums: IntArray, target: Int): Int {
+ val n = nums.size
+ // 求解问题 f(0, n-1)
+ return dfs(nums, target, 0, n - 1)
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_recur.zig"
diff --git a/docs/chapter_divide_and_conquer/build_binary_tree_problem.md b/docs/chapter_divide_and_conquer/build_binary_tree_problem.md
index 4ed9a14b5..9f4e6b9c0 100644
--- a/docs/chapter_divide_and_conquer/build_binary_tree_problem.md
+++ b/docs/chapter_divide_and_conquer/build_binary_tree_problem.md
@@ -445,6 +445,37 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="build_tree.kt"
+ /* 构建二叉树:分治 */
+ fun dfs(preorder: IntArray, inorderMap: Map, i: Int, l: Int, r: Int): TreeNode? {
+ // 子树区间为空时终止
+ if (r - l < 0) return null
+ // 初始化根节点
+ val root = TreeNode(preorder[i])
+ // 查询 m ,从而划分左右子树
+ val m = inorderMap[preorder[i]]!!
+ // 子问题:构建左子树
+ root.left = dfs(preorder, inorderMap, i + 1, l, m - 1)
+ // 子问题:构建右子树
+ root.right = dfs(preorder, inorderMap, i + 1 + m - l, m + 1, r)
+ // 返回根节点
+ return root
+ }
+
+ /* 构建二叉树 */
+ fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
+ // 初始化哈希表,存储 inorder 元素到索引的映射
+ val inorderMap: MutableMap = HashMap()
+ for (i in inorder.indices) {
+ inorderMap[inorder[i]] = i
+ }
+ val root = dfs(preorder, inorderMap, 0, 0, inorder.size - 1)
+ return root
+ }
+ ```
+
=== "Zig"
```zig title="build_tree.zig"
diff --git a/docs/chapter_divide_and_conquer/hanota_problem.md b/docs/chapter_divide_and_conquer/hanota_problem.md
index 9a1abd336..c0072e82e 100644
--- a/docs/chapter_divide_and_conquer/hanota_problem.md
+++ b/docs/chapter_divide_and_conquer/hanota_problem.md
@@ -473,6 +473,40 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="hanota.kt"
+ /* 移动一个圆盘 */
+ fun move(src: MutableList, tar: MutableList) {
+ // 从 src 顶部拿出一个圆盘
+ val pan: Int = src.removeAt(src.size - 1)
+ // 将圆盘放入 tar 顶部
+ tar.add(pan)
+ }
+
+ /* 求解汉诺塔问题 f(i) */
+ fun dfs(i: Int, src: MutableList, buf: MutableList, tar: MutableList) {
+ // 若 src 只剩下一个圆盘,则直接将其移到 tar
+ if (i == 1) {
+ move(src, tar)
+ return
+ }
+ // 子问题 f(i-1) :将 src 顶部 i-1 个圆盘借助 tar 移到 buf
+ dfs(i - 1, src, tar, buf)
+ // 子问题 f(1) :将 src 剩余一个圆盘移到 tar
+ move(src, tar)
+ // 子问题 f(i-1) :将 buf 顶部 i-1 个圆盘借助 src 移到 tar
+ dfs(i - 1, buf, src, tar)
+ }
+
+ /* 求解汉诺塔问题 */
+ fun solveHanota(A: MutableList, B: MutableList, C: MutableList) {
+ val n = A.size
+ // 将 A 顶部 n 个圆盘借助 B 移到 C
+ dfs(n, A, B, C)
+ }
+ ```
+
=== "Zig"
```zig title="hanota.zig"
diff --git a/docs/chapter_dynamic_programming/dp_problem_features.md b/docs/chapter_dynamic_programming/dp_problem_features.md
index aab06321b..b6d99f287 100644
--- a/docs/chapter_dynamic_programming/dp_problem_features.md
+++ b/docs/chapter_dynamic_programming/dp_problem_features.md
@@ -281,6 +281,26 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="min_cost_climbing_stairs_dp.kt"
+ /* 爬楼梯最小代价:动态规划 */
+ fun minCostClimbingStairsDP(cost: IntArray): Int {
+ val n = cost.size - 1
+ if (n == 1 || n == 2) return cost[n]
+ // 初始化 dp 表,用于存储子问题的解
+ val dp = IntArray(n + 1)
+ // 初始状态:预设最小子问题的解
+ dp[1] = cost[1]
+ dp[2] = cost[2]
+ // 状态转移:从较小子问题逐步求解较大子问题
+ for (i in 3..n) {
+ dp[i] = (min(dp[i - 1].toDouble(), dp[i - 2].toDouble()) + cost[i]).toInt()
+ }
+ return dp[n]
+ }
+ ```
+
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
@@ -522,6 +542,24 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="min_cost_climbing_stairs_dp.kt"
+ /* 爬楼梯最小代价:空间优化后的动态规划 */
+ fun minCostClimbingStairsDPComp(cost: IntArray): Int {
+ val n = cost.size - 1
+ if (n == 1 || n == 2) return cost[n]
+ var a = cost[1]
+ var b = cost[2]
+ for (i in 3..n) {
+ val tmp = b
+ b = (min(a.toDouble(), tmp.toDouble()) + cost[i]).toInt()
+ a = tmp
+ }
+ return b
+ }
+ ```
+
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
@@ -858,6 +896,30 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="climbing_stairs_constraint_dp.kt"
+ /* 带约束爬楼梯:动态规划 */
+ fun climbingStairsConstraintDP(n: Int): Int {
+ if (n == 1 || n == 2) {
+ return 1
+ }
+ // 初始化 dp 表,用于存储子问题的解
+ val dp = Array(n + 1) { IntArray(3) }
+ // 初始状态:预设最小子问题的解
+ dp[1][1] = 1
+ dp[1][2] = 0
+ dp[2][1] = 0
+ dp[2][2] = 1
+ // 状态转移:从较小子问题逐步求解较大子问题
+ for (i in 3..n) {
+ dp[i][1] = dp[i - 1][2]
+ dp[i][2] = dp[i - 2][1] + dp[i - 2][2]
+ }
+ return dp[n][1] + dp[n][2]
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_constraint_dp.zig"
diff --git a/docs/chapter_dynamic_programming/dp_solution_pipeline.md b/docs/chapter_dynamic_programming/dp_solution_pipeline.md
index 8db036484..5502695aa 100644
--- a/docs/chapter_dynamic_programming/dp_solution_pipeline.md
+++ b/docs/chapter_dynamic_programming/dp_solution_pipeline.md
@@ -345,6 +345,31 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="min_path_sum.kt"
+ /* 最小路径和:暴力搜索 */
+ fun minPathSumDFS(
+ grid: Array>,
+ i: Int,
+ j: Int
+ ): Int {
+ // 若为左上角单元格,则终止搜索
+ if (i == 0 && j == 0) {
+ return grid[0][0]
+ }
+ // 若行列索引越界,则返回 +∞ 代价
+ if (i < 0 || j < 0) {
+ return Int.MAX_VALUE
+ }
+ // 计算从左上角到 (i-1, j) 和 (i, j-1) 的最小路径代价
+ 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()
+ }
+ ```
+
=== "Zig"
```zig title="min_path_sum.zig"
@@ -675,6 +700,37 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="min_path_sum.kt"
+ /* 最小路径和:记忆化搜索 */
+ fun minPathSumDFSMem(
+ grid: Array>,
+ mem: Array>,
+ i: Int,
+ j: Int
+ ): Int {
+ // 若为左上角单元格,则终止搜索
+ if (i == 0 && j == 0) {
+ return grid[0][0]
+ }
+ // 若行列索引越界,则返回 +∞ 代价
+ if (i < 0 || j < 0) {
+ return Int.MAX_VALUE
+ }
+ // 若已有记录,则直接返回
+ if (mem[i][j] != -1) {
+ return mem[i][j]
+ }
+ // 左边和上边单元格的最小路径代价
+ 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()
+ return mem[i][j]
+ }
+ ```
+
=== "Zig"
```zig title="min_path_sum.zig"
@@ -1026,6 +1082,35 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="min_path_sum.kt"
+ /* 最小路径和:动态规划 */
+ fun minPathSumDP(grid: Array>): Int {
+ val n = grid.size
+ val m = grid[0].size
+ // 初始化 dp 表
+ val dp = Array(n) { IntArray(m) }
+ dp[0][0] = grid[0][0]
+ // 状态转移:首行
+ for (j in 1..>): Int {
+ val n = grid.size
+ val m = grid[0].size
+ // 初始化 dp 表
+ val dp = IntArray(m)
+ // 状态转移:首行
+ dp[0] = grid[0][0]
+ for (j in 1..,
+ state: Int,
+ n: Int,
+ res: MutableList
+ ) {
+ // 当爬到第 n 阶时,方案数量加 1
+ if (state == n) res[0] = res[0] + 1
+ // 遍历所有选择
+ for (choice in choices) {
+ // 剪枝:不允许越过第 n 阶
+ if (state + choice > n) continue
+ // 尝试:做出选择,更新状态
+ backtrack(choices, state + choice, n, res)
+ // 回退
+ }
+ }
+
+ /* 爬楼梯:回溯 */
+ fun climbingStairsBacktrack(n: Int): Int {
+ val choices = mutableListOf(1, 2) // 可选择向上爬 1 阶或 2 阶
+ val state = 0 // 从第 0 阶开始爬
+ val res = ArrayList()
+ res.add(0) // 使用 res[0] 记录方案数量
+ backtrack(choices, state, n, res)
+ return res[0]
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_backtrack.zig"
@@ -629,6 +662,24 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="climbing_stairs_dfs.kt"
+ /* 搜索 */
+ fun dfs(i: Int): Int {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2) return i
+ // dp[i] = dp[i-1] + dp[i-2]
+ val count = dfs(i - 1) + dfs(i - 2)
+ return count
+ }
+
+ /* 爬楼梯:搜索 */
+ fun climbingStairsDFS(n: Int): Int {
+ return dfs(n)
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_dfs.zig"
@@ -967,6 +1018,31 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="climbing_stairs_dfs_mem.kt"
+ /* 记忆化搜索 */
+ fun dfs(i: Int, mem: IntArray): Int {
+ // 已知 dp[1] 和 dp[2] ,返回之
+ if (i == 1 || i == 2) return i
+ // 若存在记录 dp[i] ,则直接返回之
+ if (mem[i] != -1) return mem[i]
+ // dp[i] = dp[i-1] + dp[i-2]
+ val count = dfs(i - 1, mem) + dfs(i - 2, mem)
+ // 记录 dp[i]
+ mem[i] = count
+ return count
+ }
+
+ /* 爬楼梯:记忆化搜索 */
+ fun climbingStairsDFSMem(n: Int): Int {
+ // mem[i] 记录爬到第 i 阶的方案总数,-1 代表无记录
+ val mem = IntArray(n + 1)
+ Arrays.fill(mem, -1)
+ return dfs(n, mem)
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_dfs_mem.zig"
@@ -1234,6 +1310,25 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="climbing_stairs_dp.kt"
+ /* 爬楼梯:动态规划 */
+ fun climbingStairsDP(n: Int): Int {
+ if (n == 1 || n == 2) return n
+ // 初始化 dp 表,用于存储子问题的解
+ val dp = IntArray(n + 1)
+ // 初始状态:预设最小子问题的解
+ dp[1] = 1
+ dp[2] = 2
+ // 状态转移:从较小子问题逐步求解较大子问题
+ for (i in 3..n) {
+ dp[i] = dp[i - 1] + dp[i - 2]
+ }
+ return dp[n]
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_dp.zig"
@@ -1462,6 +1557,23 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="climbing_stairs_dp.kt"
+ /* 爬楼梯:空间优化后的动态规划 */
+ fun climbingStairsDPComp(n: Int): Int {
+ if (n == 1 || n == 2) return n
+ var a = 1
+ var b = 2
+ for (i in 3..n) {
+ val tmp = b
+ b += a
+ a = tmp
+ }
+ return b
+ }
+ ```
+
=== "Zig"
```zig title="climbing_stairs_dp.zig"
diff --git a/docs/chapter_dynamic_programming/knapsack_problem.md b/docs/chapter_dynamic_programming/knapsack_problem.md
index 58f825393..c8ef3c9a9 100644
--- a/docs/chapter_dynamic_programming/knapsack_problem.md
+++ b/docs/chapter_dynamic_programming/knapsack_problem.md
@@ -295,6 +295,32 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="knapsack.kt"
+ /* 0-1 背包:暴力搜索 */
+ fun knapsackDFS(
+ wgt: IntArray,
+ value: IntArray,
+ i: Int,
+ c: Int
+ ): Int {
+ // 若已选完所有物品或背包无剩余容量,则返回价值 0
+ if (i == 0 || c == 0) {
+ return 0
+ }
+ // 若超过背包容量,则只能选择不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFS(wgt, value, i - 1, c)
+ }
+ // 计算不放入和放入物品 i 的最大价值
+ 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()
+ }
+ ```
+
=== "Zig"
```zig title="knapsack.zig"
@@ -633,6 +659,38 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="knapsack.kt"
+ /* 0-1 背包:记忆化搜索 */
+ fun knapsackDFSMem(
+ wgt: IntArray,
+ value: IntArray,
+ mem: Array,
+ i: Int,
+ c: Int
+ ): Int {
+ // 若已选完所有物品或背包无剩余容量,则返回价值 0
+ if (i == 0 || c == 0) {
+ return 0
+ }
+ // 若已有记录,则直接返回
+ if (mem[i][c] != -1) {
+ return mem[i][c]
+ }
+ // 若超过背包容量,则只能选择不放入背包
+ if (wgt[i - 1] > c) {
+ return knapsackDFSMem(wgt, value, mem, i - 1, c)
+ }
+ // 计算不放入和放入物品 i 的最大价值
+ 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()
+ return mem[i][c]
+ }
+ ```
+
=== "Zig"
```zig title="knapsack.zig"
@@ -962,6 +1020,35 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="knapsack.kt"
+ /* 0-1 背包:动态规划 */
+ fun knapsackDP(
+ wgt: IntArray,
+ value: IntArray,
+ cap: Int
+ ): Int {
+ val n = wgt.size
+ // 初始化 dp 表
+ val dp = Array(n + 1) { IntArray(cap + 1) }
+ // 状态转移
+ for (i in 1..n) {
+ for (c in 1..cap) {
+ if (wgt[i - 1] > c) {
+ // 若超过背包容量,则不选物品 i
+ 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()
+ }
+ }
+ }
+ return dp[n][cap]
+ }
+ ```
+
=== "Zig"
```zig title="knapsack.zig"
@@ -1321,6 +1408,33 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="knapsack.kt"
+ /* 0-1 背包:空间优化后的动态规划 */
+ fun knapsackDPComp(
+ wgt: IntArray,
+ value: IntArray,
+ cap: Int
+ ): Int {
+ val n = wgt.size
+ // 初始化 dp 表
+ val dp = IntArray(cap + 1)
+ // 状态转移
+ for (i in 1..n) {
+ // 倒序遍历
+ for (c in cap downTo 1) {
+ if (wgt[i - 1] <= c) {
+ // 不选和选物品 i 这两种方案的较大值
+ dp[c] =
+ max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
+ }
+ }
+ }
+ return dp[cap]
+ }
+ ```
+
=== "Zig"
```zig title="knapsack.zig"
diff --git a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md
index aae7dd99f..42604d023 100644
--- a/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md
+++ b/docs/chapter_dynamic_programming/unbounded_knapsack_problem.md
@@ -323,6 +323,35 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="unbounded_knapsack.kt"
+ /* 完全背包:动态规划 */
+ fun unboundedKnapsackDP(
+ wgt: IntArray,
+ value: IntArray,
+ cap: Int
+ ): Int {
+ val n = wgt.size
+ // 初始化 dp 表
+ val dp = Array(n + 1) { IntArray(cap + 1) }
+ // 状态转移
+ for (i in 1..n) {
+ for (c in 1..cap) {
+ if (wgt[i - 1] > c) {
+ // 若超过背包容量,则不选物品 i
+ 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()
+ }
+ }
+ }
+ return dp[n][cap]
+ }
+ ```
+
=== "Zig"
```zig title="unbounded_knapsack.zig"
@@ -648,6 +677,35 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="unbounded_knapsack.kt"
+ /* 完全背包:空间优化后的动态规划 */
+ fun unboundedKnapsackDPComp(
+ wgt: IntArray,
+ value: IntArray,
+ cap: Int
+ ): Int {
+ val n = wgt.size
+ // 初始化 dp 表
+ val dp = IntArray(cap + 1)
+ // 状态转移
+ for (i in 1..n) {
+ for (c in 1..cap) {
+ if (wgt[i - 1] > c) {
+ // 若超过背包容量,则不选物品 i
+ dp[c] = dp[c]
+ } else {
+ // 不选和选物品 i 这两种方案的较大值
+ dp[c] =
+ max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
+ }
+ }
+ }
+ return dp[cap]
+ }
+ ```
+
=== "Zig"
```zig title="unbounded_knapsack.zig"
@@ -1063,6 +1121,36 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="coin_change.kt"
+ /* 零钱兑换:动态规划 */
+ fun coinChangeDP(coins: IntArray, amt: Int): Int {
+ val n = coins.size
+ val MAX = amt + 1
+ // 初始化 dp 表
+ val dp = Array(n + 1) { IntArray(amt + 1) }
+ // 状态转移:首行首列
+ for (a in 1..amt) {
+ dp[0][a] = MAX
+ }
+ // 状态转移:其余行和列
+ for (i in 1..n) {
+ for (a in 1..amt) {
+ if (coins[i - 1] > a) {
+ // 若超过目标金额,则不选硬币 i
+ 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()
+ }
+ }
+ }
+ return if (dp[n][amt] != MAX) dp[n][amt] else -1
+ }
+ ```
+
=== "Zig"
```zig title="coin_change.zig"
@@ -1453,6 +1541,33 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="coin_change.kt"
+ /* 零钱兑换:空间优化后的动态规划 */
+ fun coinChangeDPComp(coins: IntArray, amt: Int): Int {
+ val n = coins.size
+ val MAX = amt + 1
+ // 初始化 dp 表
+ val dp = IntArray(amt + 1)
+ Arrays.fill(dp, MAX)
+ dp[0] = 0
+ // 状态转移
+ for (i in 1..n) {
+ for (a in 1..amt) {
+ if (coins[i - 1] > a) {
+ // 若超过目标金额,则不选硬币 i
+ dp[a] = dp[a]
+ } else {
+ // 不选和选硬币 i 这两种方案的较小值
+ dp[a] = min(dp[a].toDouble(), (dp[a - coins[i - 1]] + 1).toDouble()).toInt()
+ }
+ }
+ }
+ return if (dp[amt] != MAX) dp[amt] else -1
+ }
+ ```
+
=== "Zig"
```zig title="coin_change.zig"
@@ -1832,6 +1947,34 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="coin_change_ii.kt"
+ /* 零钱兑换 II:动态规划 */
+ fun coinChangeIIDP(coins: IntArray, amt: Int): Int {
+ val n = coins.size
+ // 初始化 dp 表
+ val dp = Array(n + 1) { IntArray(amt + 1) }
+ // 初始化首列
+ for (i in 0..n) {
+ dp[i][0] = 1
+ }
+ // 状态转移
+ for (i in 1..n) {
+ for (a in 1..amt) {
+ if (coins[i - 1] > a) {
+ // 若超过目标金额,则不选硬币 i
+ dp[i][a] = dp[i - 1][a]
+ } else {
+ // 不选和选硬币 i 这两种方案之和
+ dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1]]
+ }
+ }
+ }
+ return dp[n][amt]
+ }
+ ```
+
=== "Zig"
```zig title="coin_change_ii.zig"
@@ -2145,6 +2288,31 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="coin_change_ii.kt"
+ /* 零钱兑换 II:空间优化后的动态规划 */
+ fun coinChangeIIDPComp(coins: IntArray, amt: Int): Int {
+ val n = coins.size
+ // 初始化 dp 表
+ val dp = IntArray(amt + 1)
+ dp[0] = 1
+ // 状态转移
+ for (i in 1..n) {
+ for (a in 1..amt) {
+ if (coins[i - 1] > a) {
+ // 若超过目标金额,则不选硬币 i
+ dp[a] = dp[a]
+ } else {
+ // 不选和选硬币 i 这两种方案之和
+ dp[a] = dp[a] + dp[a - coins[i - 1]]
+ }
+ }
+ }
+ return dp[amt]
+ }
+ ```
+
=== "Zig"
```zig title="coin_change_ii.zig"
diff --git a/docs/chapter_graph/graph_operations.md b/docs/chapter_graph/graph_operations.md
index f6079aefd..1bbb43caf 100644
--- a/docs/chapter_graph/graph_operations.md
+++ b/docs/chapter_graph/graph_operations.md
@@ -1039,6 +1039,91 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="graph_adjacency_matrix.kt"
+ /* 基于邻接矩阵实现的无向图类 */
+ class GraphAdjMat(vertices: IntArray, edges: Array) {
+ val vertices: MutableList = ArrayList() // 顶点列表,元素代表“顶点值”,索引代表“顶点索引”
+ val adjMat: MutableList> = ArrayList() // 邻接矩阵,行列索引对应“顶点索引”
+
+ /* 构造函数 */
+ init {
+ // 添加顶点
+ for (vertex in vertices) {
+ addVertex(vertex)
+ }
+ // 添加边
+ // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引
+ for (edge in edges) {
+ addEdge(edge[0], edge[1])
+ }
+ }
+
+ /* 获取顶点数量 */
+ fun size(): Int {
+ return vertices.size
+ }
+
+ /* 添加顶点 */
+ fun addVertex(value: Int) {
+ val n = size()
+ // 向顶点列表中添加新顶点的值
+ vertices.add(value)
+ // 在邻接矩阵中添加一行
+ val newRow: MutableList = mutableListOf()
+ for (j in 0..= size()) throw IndexOutOfBoundsException()
+ // 在顶点列表中移除索引 index 的顶点
+ vertices.removeAt(index)
+ // 在邻接矩阵中删除索引 index 的行
+ adjMat.removeAt(index)
+ // 在邻接矩阵中删除索引 index 的列
+ for (row in adjMat) {
+ row.removeAt(index)
+ }
+ }
+
+ /* 添加边 */
+ // 参数 i, j 对应 vertices 元素索引
+ fun addEdge(i: Int, j: Int) {
+ // 索引越界与相等处理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
+ // 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i)
+ adjMat[i][j] = 1;
+ adjMat[j][i] = 1;
+ }
+
+ /* 删除边 */
+ // 参数 i, j 对应 vertices 元素索引
+ fun removeEdge(i: Int, j: Int) {
+ // 索引越界与相等处理
+ if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
+ adjMat[i][j] = 0;
+ adjMat[j][i] = 0;
+ }
+
+ /* 打印邻接矩阵 */
+ fun print() {
+ print("顶点列表 = ")
+ println(vertices);
+ println("邻接矩阵 =");
+ printMatrix(adjMat)
+ }
+ }
+ ```
+
=== "Zig"
```zig title="graph_adjacency_matrix.zig"
@@ -2061,6 +2146,81 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="graph_adjacency_list.kt"
+ /* 基于邻接表实现的无向图类 */
+ class GraphAdjList(edges: Array>) {
+ // 邻接表,key:顶点,value:该顶点的所有邻接顶点
+ val adjList: MutableMap> = HashMap()
+
+ /* 构造函数 */
+ init {
+ // 添加所有顶点和边
+ for (edge in edges) {
+ addVertex(edge[0]!!);
+ addVertex(edge[1]!!);
+ addEdge(edge[0]!!, edge[1]!!);
+ }
+ }
+
+ /* 获取顶点数量 */
+ fun size(): Int {
+ return adjList.size
+ }
+
+ /* 添加边 */
+ fun addEdge(vet1: Vertex, vet2: Vertex) {
+ if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2)
+ throw IllegalArgumentException()
+ // 添加边 vet1 - vet2
+ adjList[vet1]?.add(vet2)
+ adjList[vet2]?.add(vet1);
+ }
+
+ /* 删除边 */
+ fun removeEdge(vet1: Vertex, vet2: Vertex) {
+ if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2)
+ throw IllegalArgumentException()
+ // 删除边 vet1 - vet2
+ adjList[vet1]?.remove(vet2);
+ adjList[vet2]?.remove(vet1);
+ }
+
+ /* 添加顶点 */
+ fun addVertex(vet: Vertex) {
+ if (adjList.containsKey(vet))
+ return
+ // 在邻接表中添加一个新链表
+ adjList[vet] = mutableListOf()
+ }
+
+ /* 删除顶点 */
+ fun removeVertex(vet: Vertex) {
+ if (!adjList.containsKey(vet))
+ throw IllegalArgumentException()
+ // 在邻接表中删除顶点 vet 对应的链表
+ adjList.remove(vet);
+ // 遍历其他顶点的链表,删除所有包含 vet 的边
+ for (list in adjList.values) {
+ list.remove(vet)
+ }
+ }
+
+ /* 打印邻接表 */
+ fun print() {
+ println("邻接表 =")
+ for (pair in adjList.entries) {
+ val tmp = ArrayList()
+ for (vertex in pair.value) {
+ tmp.add(vertex.value)
+ }
+ println("${pair.key.value}: $tmp,")
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="graph_adjacency_list.zig"
diff --git a/docs/chapter_graph/graph_traversal.md b/docs/chapter_graph/graph_traversal.md
index 49337afcb..e055930c1 100644
--- a/docs/chapter_graph/graph_traversal.md
+++ b/docs/chapter_graph/graph_traversal.md
@@ -413,6 +413,37 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
}
```
+=== "Kotlin"
+
+ ```kotlin title="graph_bfs.kt"
+ /* 广度优先遍历 */
+ // 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
+ fun graphBFS(graph: GraphAdjList, startVet: Vertex): List {
+ // 顶点遍历序列
+ val res: MutableList = ArrayList()
+ // 哈希表,用于记录已被访问过的顶点
+ val visited: MutableSet = HashSet()
+ visited.add(startVet)
+ // 队列用于实现 BFS
+ val que: Queue = LinkedList()
+ que.offer(startVet)
+ // 以顶点 vet 为起点,循环直至访问完所有顶点
+ while (!que.isEmpty()) {
+ val vet = que.poll() // 队首顶点出队
+ res.add(vet) // 记录访问顶点
+ // 遍历该顶点的所有邻接顶点
+ for (adjVet in graph.adjList[vet]!!) {
+ if (visited.contains(adjVet)) continue // 跳过已被访问的顶点
+
+ que.offer(adjVet) // 只入队未访问的顶点
+ visited.add(adjVet) // 标记该顶点已被访问
+ }
+ }
+ // 返回顶点遍历序列
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="graph_bfs.zig"
@@ -819,6 +850,41 @@ BFS 通常借助队列来实现,代码如下所示。队列具有“先入先
}
```
+=== "Kotlin"
+
+ ```kotlin title="graph_dfs.kt"
+ /* 深度优先遍历辅助函数 */
+ fun dfs(
+ graph: GraphAdjList,
+ visited: MutableSet,
+ res: MutableList,
+ vet: Vertex?
+ ) {
+ res.add(vet) // 记录访问顶点
+ visited.add(vet) // 标记该顶点已被访问
+ // 遍历该顶点的所有邻接顶点
+ for (adjVet in graph.adjList[vet]!!) {
+ if (visited.contains(adjVet)) continue // 跳过已被访问的顶点
+ // 递归访问邻接顶点
+ dfs(graph, visited, res, adjVet)
+ }
+ }
+
+ /* 深度优先遍历 */
+ // 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
+ fun graphDFS(
+ graph: GraphAdjList,
+ startVet: Vertex?
+ ): List {
+ // 顶点遍历序列
+ val res: MutableList = ArrayList()
+ // 哈希表,用于记录已被访问过的顶点
+ val visited: MutableSet = HashSet()
+ dfs(graph, visited, res, startVet)
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="graph_dfs.zig"
diff --git a/docs/chapter_greedy/fractional_knapsack_problem.md b/docs/chapter_greedy/fractional_knapsack_problem.md
index 57736823d..5d15d877d 100644
--- a/docs/chapter_greedy/fractional_knapsack_problem.md
+++ b/docs/chapter_greedy/fractional_knapsack_problem.md
@@ -456,6 +456,78 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="fractional_knapsack.kt"
+ /* 物品 */
+ class Item(
+ val w: Int, // 物品
+ val v: Int // 物品价值
+ )
+
+ /* 分数背包:贪心 */
+ fun fractionalKnapsack(
+ wgt: IntArray,
+ value: IntArray,
+ c: Int
+ ): Double {
+ // 创建物品列表,包含两个属性:重量、价值
+ var cap = c
+ val items = arrayOfNulls- (wgt.size)
+ for (i in wgt.indices) {
+ items[i] = Item(wgt[i], value[i])
+ }
+ // 按照单位价值 item.v / item.w 从高到低进行排序
+ Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) })
+ // 循环贪心选择
+ var res = 0.0
+ for (item in items) {
+ if (item!!.w <= cap) {
+ // 若剩余容量充足,则将当前物品整个装进背包
+ res += item.v.toDouble()
+ cap -= item.w
+ } else {
+ // 若剩余容量不足,则将当前物品的一部分装进背包
+ res += item.v.toDouble() / item.w * cap
+ // 已无剩余容量,因此跳出循环
+ break
+ }
+ }
+ return res
+ }
+
+ /* 分数背包:贪心 */
+ fun fractionalKnapsack(
+ wgt: IntArray,
+ value: IntArray,
+ c: Int
+ ): Double {
+ // 创建物品列表,包含两个属性:重量、价值
+ var cap = c
+ val items = arrayOfNulls
- (wgt.size)
+ for (i in wgt.indices) {
+ items[i] = Item(wgt[i], value[i])
+ }
+ // 按照单位价值 item.v / item.w 从高到低进行排序
+ Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) })
+ // 循环贪心选择
+ var res = 0.0
+ for (item in items) {
+ if (item!!.w <= cap) {
+ // 若剩余容量充足,则将当前物品整个装进背包
+ res += item.v.toDouble()
+ cap -= item.w
+ } else {
+ // 若剩余容量不足,则将当前物品的一部分装进背包
+ res += item.v.toDouble() / item.w * cap
+ // 已无剩余容量,因此跳出循环
+ break
+ }
+ }
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="fractional_knapsack.zig"
diff --git a/docs/chapter_greedy/greedy_algorithm.md b/docs/chapter_greedy/greedy_algorithm.md
index f9baf3968..b8880b360 100644
--- a/docs/chapter_greedy/greedy_algorithm.md
+++ b/docs/chapter_greedy/greedy_algorithm.md
@@ -283,6 +283,30 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="coin_change_greedy.kt"
+ /* 零钱兑换:贪心 */
+ fun coinChangeGreedy(coins: IntArray, amt: Int): Int {
+ // 假设 coins 列表有序
+ var am = amt
+ var i = coins.size - 1
+ var count = 0
+ // 循环进行贪心选择,直到无剩余金额
+ while (am > 0) {
+ // 找到小于且最接近剩余金额的硬币
+ while (i > 0 && coins[i] > am) {
+ i--
+ }
+ // 选择 coins[i]
+ am -= coins[i]
+ count++
+ }
+ // 若未找到可行方案,则返回 -1
+ return if (am == 0) count else -1
+ }
+ ```
+
=== "Zig"
```zig title="coin_change_greedy.zig"
diff --git a/docs/chapter_greedy/max_capacity_problem.md b/docs/chapter_greedy/max_capacity_problem.md
index e1b20759f..07bc11803 100644
--- a/docs/chapter_greedy/max_capacity_problem.md
+++ b/docs/chapter_greedy/max_capacity_problem.md
@@ -368,6 +368,32 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="max_capacity.kt"
+ /* 最大容量:贪心 */
+ fun maxCapacity(ht: IntArray): Int {
+ // 初始化 i, j,使其分列数组两端
+ var i = 0
+ var j = ht.size - 1
+ // 初始最大容量为 0
+ var res = 0
+ // 循环贪心选择,直至两板相遇
+ while (i < j) {
+ // 更新最大容量
+ val cap = (min(ht[i].toDouble(), ht[j].toDouble()) * (j - i)).toInt()
+ res = max(res.toDouble(), cap.toDouble()).toInt()
+ // 向内移动短板
+ if (ht[i] < ht[j]) {
+ i++
+ } else {
+ j--
+ }
+ }
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="max_capacity.zig"
diff --git a/docs/chapter_greedy/max_product_cutting_problem.md b/docs/chapter_greedy/max_product_cutting_problem.md
index 9a74ba2f2..5eff8ffd0 100644
--- a/docs/chapter_greedy/max_product_cutting_problem.md
+++ b/docs/chapter_greedy/max_product_cutting_problem.md
@@ -343,6 +343,31 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="max_product_cutting.kt"
+ /* 最大切分乘积:贪心 */
+ fun maxProductCutting(n: Int): Int {
+ // 当 n <= 3 时,必须切分出一个 1
+ if (n <= 3) {
+ return 1 * (n - 1)
+ }
+ // 贪心地切分出 3 ,a 为 3 的个数,b 为余数
+ val a = n / 3
+ val b = n % 3
+ if (b == 1) {
+ // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2
+ return 3.0.pow((a - 1).toDouble()).toInt() * 2 * 2
+ }
+ if (b == 2) {
+ // 当余数为 2 时,不做处理
+ return 3.0.pow(a.toDouble()).toInt() * 2 * 2
+ }
+ // 当余数为 0 时,不做处理
+ return 3.0.pow(a.toDouble()).toInt()
+ }
+ ```
+
=== "Zig"
```zig title="max_product_cutting.zig"
diff --git a/docs/chapter_hashing/hash_algorithm.md b/docs/chapter_hashing/hash_algorithm.md
index 8346c461d..53575f171 100644
--- a/docs/chapter_hashing/hash_algorithm.md
+++ b/docs/chapter_hashing/hash_algorithm.md
@@ -554,6 +554,46 @@ index = hash(key) % capacity
}
```
+=== "Kotlin"
+
+ ```kotlin title="simple_hash.kt"
+ /* 加法哈希 */
+ fun addHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = (hash + c.code) % MODULUS
+ }
+ return hash.toInt()
+ }
+
+ /* 乘法哈希 */
+ fun mulHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = (31 * hash + c.code) % MODULUS
+ }
+ return hash.toInt()
+ }
+
+ /* 异或哈希 */
+ fun xorHash(key: String): Int {
+ var hash = 0
+ for (c in key.toCharArray()) {
+ hash = hash xor c.code
+ }
+ return hash and MODULUS
+ }
+
+ /* 旋转哈希 */
+ fun rotHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = ((hash shl 4) xor (hash shr 28) xor c.code.toLong()) % MODULUS
+ }
+ return hash.toInt()
+ }
+ ```
+
=== "Zig"
```zig title="simple_hash.zig"
@@ -868,6 +908,12 @@ $$
// C 未提供内置 hash code 函数
```
+=== "Kotlin"
+
+ ```kotlin title="built_in_hash.kt"
+
+ ```
+
=== "Zig"
```zig title="built_in_hash.zig"
diff --git a/docs/chapter_hashing/hash_collision.md b/docs/chapter_hashing/hash_collision.md
index 208f93bc8..fa50ee408 100644
--- a/docs/chapter_hashing/hash_collision.md
+++ b/docs/chapter_hashing/hash_collision.md
@@ -1311,6 +1311,121 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map_chaining.kt"
+ /* 链式地址哈希表 */
+ class HashMapChaining() {
+ var size: Int // 键值对数量
+ var capacity: Int // 哈希表容量
+ val loadThres: Double // 触发扩容的负载因子阈值
+ val extendRatio: Int // 扩容倍数
+ var buckets: MutableList> // 桶数组
+
+ /* 构造方法 */
+ init {
+ size = 0
+ capacity = 4
+ loadThres = 2.0 / 3.0
+ extendRatio = 2
+ buckets = ArrayList(capacity)
+ for (i in 0.. loadThres) {
+ extend()
+ }
+ val index = hashFunc(key)
+ val bucket = buckets[index]
+ // 遍历桶,若遇到指定 key ,则更新对应 val 并返回
+ for (pair in bucket) {
+ if (pair.key == key) {
+ pair.value = value
+ return
+ }
+ }
+ // 若无该 key ,则将键值对添加至尾部
+ val pair = Pair(key, value)
+ bucket.add(pair)
+ size++
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ val bucket = buckets[index]
+ // 遍历桶,从中删除键值对
+ for (pair in bucket) {
+ if (pair.key == key) {
+ bucket.remove(pair)
+ size--
+ break
+ }
+ }
+ }
+
+ /* 扩容哈希表 */
+ fun extend() {
+ // 暂存原哈希表
+ val bucketsTmp = buckets
+ // 初始化扩容后的新哈希表
+ capacity *= extendRatio
+ // mutablelist 无固定大小
+ buckets = mutableListOf()
+ for (i in 0..()
+ for (pair in bucket) {
+ val k = pair.key
+ val v = pair.value
+ res.add("$k -> $v")
+ }
+ println(res)
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="hash_map_chaining.zig"
@@ -2831,6 +2946,132 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```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 // 桶数组
+ private val TOMBSTONE = Pair(-1, "-1") // 删除标记
+
+ /* 构造方法 */
+ init {
+ buckets = arrayOfNulls(capacity)
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ return key % capacity
+ }
+
+ /* 负载因子 */
+ fun loadFactor(): Double {
+ return (size / capacity).toDouble()
+ }
+
+ /* 搜索 key 对应的桶索引 */
+ fun findBucket(key: Int): Int {
+ var index = hashFunc(key)
+ var firstTombstone = -1
+ // 线性探测,当遇到空桶时跳出
+ while (buckets[index] != null) {
+ // 若遇到 key ,返回对应的桶索引
+ if (buckets[index]?.key == key) {
+ // 若之前遇到了删除标记,则将键值对移动至该索引处
+ if (firstTombstone != -1) {
+ buckets[firstTombstone] = buckets[index]
+ buckets[index] = TOMBSTONE
+ return firstTombstone // 返回移动后的桶索引
+ }
+ return index // 返回桶索引
+ }
+ // 记录遇到的首个删除标记
+ if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {
+ firstTombstone = index
+ }
+ // 计算桶索引,越过尾部则返回头部
+ index = (index + 1) % capacity
+ }
+ // 若 key 不存在,则返回添加点的索引
+ return if (firstTombstone == -1) index else firstTombstone
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则返回对应 val
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ return buckets[index]?.value
+ }
+ // 若键值对不存在,则返回 null
+ return null
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ // 当负载因子超过阈值时,执行扩容
+ if (loadFactor() > loadThres) {
+ extend()
+ }
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则覆盖 val 并返回
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ buckets[index]!!.value = value
+ return
+ }
+ // 若键值对不存在,则添加该键值对
+ buckets[index] = Pair(key, value)
+ size++
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则用删除标记覆盖它
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ buckets[index] = TOMBSTONE
+ size--
+ }
+ }
+
+ /* 扩容哈希表 */
+ fun extend() {
+ // 暂存原哈希表
+ val bucketsTmp = buckets
+ // 初始化扩容后的新哈希表
+ capacity *= extendRatio
+ buckets = arrayOfNulls(capacity)
+ size = 0
+ // 将键值对从原哈希表搬运至新哈希表
+ for (pair in bucketsTmp) {
+ if (pair != null && pair != TOMBSTONE) {
+ put(pair.key, pair.value)
+ }
+ }
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (pair in buckets) {
+ if (pair == null) {
+ println("null")
+ } else if (pair == TOMBSTONE) {
+ println("TOMESTOME")
+ } else {
+ println("${pair.key} -> ${pair.value}")
+ }
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="hash_map_open_addressing.zig"
diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md
index 7b5be4185..0183aed51 100755
--- a/docs/chapter_hashing/hash_map.md
+++ b/docs/chapter_hashing/hash_map.md
@@ -277,6 +277,12 @@ comments: true
// C 未提供内置哈希表
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map.kt"
+
+ ```
+
=== "Zig"
```zig title="hash_map.zig"
@@ -473,6 +479,12 @@ comments: true
// C 未提供内置哈希表
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map.kt"
+
+ ```
+
=== "Zig"
```zig title="hash_map.zig"
@@ -1525,6 +1537,166 @@ index = hash(key) % capacity
}
```
+=== "Kotlin"
+
+ ```kotlin title="array_hash_map.kt"
+ /* 键值对 */
+ class Pair(
+ var key: Int,
+ var value: String
+ )
+
+ /* 基于数组实现的哈希表 */
+ class ArrayHashMap {
+ private val buckets = arrayOfNulls(100)
+
+ init {
+ // 初始化数组,包含 100 个桶
+ for (i in 0..<100) {
+ buckets[i] = null
+ }
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ val index = key % 100
+ return index
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ val index = hashFunc(key)
+ val pair = buckets[index] ?: return null
+ return pair.value
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ val pair = Pair(key, value)
+ val index = hashFunc(key)
+ buckets[index] = pair
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ // 置为 null ,代表删除
+ buckets[index] = null
+ }
+
+ /* 获取所有键值对 */
+ fun pairSet(): MutableList {
+ val pairSet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) pairSet.add(pair)
+ }
+ return pairSet
+ }
+
+ /* 获取所有键 */
+ fun keySet(): MutableList {
+ val keySet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) keySet.add(pair.key)
+ }
+ return keySet
+ }
+
+ /* 获取所有值 */
+ fun valueSet(): MutableList {
+ val valueSet = ArrayList()
+ for (pair in buckets) {
+ pair?.let { valueSet.add(it.value) }
+ }
+ return valueSet
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (kv in pairSet()) {
+ val key = kv.key
+ val value = kv.value
+ println("${key}->${value}")
+ }
+ }
+ }
+
+ /* 基于数组实现的哈希表 */
+ class ArrayHashMap {
+ private val buckets = arrayOfNulls(100)
+
+ init {
+ // 初始化数组,包含 100 个桶
+ for (i in 0..<100) {
+ buckets[i] = null
+ }
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ val index = key % 100
+ return index
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ val index = hashFunc(key)
+ val pair = buckets[index] ?: return null
+ return pair.value
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ val pair = Pair(key, value)
+ val index = hashFunc(key)
+ buckets[index] = pair
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ // 置为 null ,代表删除
+ buckets[index] = null
+ }
+
+ /* 获取所有键值对 */
+ fun pairSet(): MutableList {
+ val pairSet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) pairSet.add(pair)
+ }
+ return pairSet
+ }
+
+ /* 获取所有键 */
+ fun keySet(): MutableList {
+ val keySet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) keySet.add(pair.key)
+ }
+ return keySet
+ }
+
+ /* 获取所有值 */
+ fun valueSet(): MutableList {
+ val valueSet = ArrayList()
+ for (pair in buckets) {
+ pair?.let { valueSet.add(it.value) }
+ }
+ return valueSet
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (kv in pairSet()) {
+ val key = kv.key
+ val value = kv.value
+ println("${key}->${value}")
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_hash_map.zig"
diff --git a/docs/chapter_heap/build_heap.md b/docs/chapter_heap/build_heap.md
index 3539c07a5..728780dab 100644
--- a/docs/chapter_heap/build_heap.md
+++ b/docs/chapter_heap/build_heap.md
@@ -185,6 +185,126 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="my_heap.kt"
+ /* 大顶堆 */
+ class MaxHeap(nums: List?) {
+ // 使用列表而非数组,这样无须考虑扩容问题
+ // 将列表元素原封不动添加进堆
+ private val maxHeap = ArrayList(nums!!)
+
+ /* 构造函数,根据输入列表建堆 */
+ init {
+ // 堆化除叶节点以外的其他所有节点
+ for (i in parent(size() - 1) downTo 0) {
+ siftDown(i)
+ }
+ }
+
+ /* 获取左子节点的索引 */
+ private fun left(i: Int): Int {
+ return 2 * i + 1
+ }
+
+ /* 获取右子节点的索引 */
+ private fun right(i: Int): Int {
+ return 2 * i + 2
+ }
+
+ /* 获取父节点的索引 */
+ private fun parent(i: Int): Int {
+ return (i - 1) / 2 // 向下整除
+ }
+
+ /* 交换元素 */
+ private fun swap(i: Int, j: Int) {
+ maxHeap[i] = maxHeap[j].also { maxHeap[j] = maxHeap[i] }
+ }
+
+ /* 获取堆大小 */
+ fun size(): Int {
+ return maxHeap.size
+ }
+
+ /* 判断堆是否为空 */
+ fun isEmpty(): Boolean {
+ /* 判断堆是否为空 */
+ return size() == 0
+ }
+
+ /* 访问堆顶元素 */
+ fun peek(): Int {
+ return maxHeap[0]
+ }
+
+ /* 元素入堆 */
+ fun push(value: Int) {
+ // 添加节点
+ maxHeap.add(value)
+ // 从底至顶堆化
+ siftUp(size() - 1)
+ }
+
+ /* 从节点 i 开始,从底至顶堆化 */
+ private fun siftUp(it: Int) {
+ // Kotlin的函数参数不可变,因此创建临时变量
+ var i = it
+ while (true) {
+ // 获取节点 i 的父节点
+ val p = parent(i)
+ // 当“越过根节点”或“节点无须修复”时,结束堆化
+ if (p < 0 || maxHeap[i] <= maxHeap[p]) break
+ // 交换两节点
+ swap(i, p)
+ // 循环向上堆化
+ i = p
+ }
+ }
+
+ /* 元素出堆 */
+ fun pop(): Int {
+ // 判空处理
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ // 交换根节点与最右叶节点(交换首元素与尾元素)
+ swap(0, size() - 1)
+ // 删除节点
+ val value = maxHeap.removeAt(size() - 1)
+ // 从顶至底堆化
+ siftDown(0)
+ // 返回堆顶元素
+ return value
+ }
+
+ /* 从节点 i 开始,从顶至底堆化 */
+ private fun siftDown(it: Int) {
+ // Kotlin的函数参数不可变,因此创建临时变量
+ var i = it
+ while (true) {
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
+ val l = left(i)
+ val r = right(i)
+ var ma = i
+ if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l
+ if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r
+ // 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出
+ if (ma == i) break
+ // 交换两节点
+ swap(i, ma)
+ // 循环向下堆化
+ i = ma
+ }
+ }
+
+ /* 打印堆(二叉树) */
+ fun print() {
+ val queue = PriorityQueue { a: Int, b: Int -> b - a }
+ queue.addAll(maxHeap)
+ printHeap(queue)
+ }
+ }
+ ```
+
=== "Zig"
```zig title="my_heap.zig"
diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md
index 33bf15032..3d0277c55 100644
--- a/docs/chapter_heap/heap.md
+++ b/docs/chapter_heap/heap.md
@@ -375,6 +375,12 @@ comments: true
// C 未提供内置 Heap 类
```
+=== "Kotlin"
+
+ ```kotlin title="heap.kt"
+
+ ```
+
=== "Zig"
```zig title="heap.zig"
@@ -611,6 +617,25 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="my_heap.kt"
+ /* 获取左子节点的索引 */
+ fun left(i: Int): Int {
+ return 2 * i + 1
+ }
+
+ /* 获取右子节点的索引 */
+ fun right(i: Int): Int {
+ return 2 * i + 2
+ }
+
+ /* 获取父节点的索引 */
+ fun parent(i: Int): Int {
+ return (i - 1) / 2 // 向下整除
+ }
+ ```
+
=== "Zig"
```zig title="my_heap.zig"
@@ -733,6 +758,15 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="my_heap.kt"
+ /* 访问堆顶元素 */
+ fun peek(): Int {
+ return maxHeap[0]
+ }
+ ```
+
=== "Zig"
```zig title="my_heap.zig"
@@ -1093,6 +1127,34 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="my_heap.kt"
+ /* 元素入堆 */
+ fun push(value: Int) {
+ // 添加节点
+ maxHeap.add(value)
+ // 从底至顶堆化
+ siftUp(size() - 1)
+ }
+
+ /* 从节点 i 开始,从底至顶堆化 */
+ fun siftUp(it: Int) {
+ // Kotlin的函数参数不可变,因此创建临时变量
+ var i = it
+ while (true) {
+ // 获取节点 i 的父节点
+ val p = parent(i)
+ // 当“越过根节点”或“节点无须修复”时,结束堆化
+ if (p < 0 || maxHeap[i] <= maxHeap[p]) break
+ // 交换两节点
+ swap(i, p)
+ // 循环向上堆化
+ i = p
+ }
+ }
+ ```
+
=== "Zig"
```zig title="my_heap.zig"
@@ -1603,6 +1665,44 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="my_heap.kt"
+ /* 元素出堆 */
+ fun pop(): Int {
+ // 判空处理
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ // 交换根节点与最右叶节点(交换首元素与尾元素)
+ swap(0, size() - 1)
+ // 删除节点
+ val value = maxHeap.removeAt(size() - 1)
+ // 从顶至底堆化
+ siftDown(0)
+ // 返回堆顶元素
+ return value
+ }
+
+ /* 从节点 i 开始,从顶至底堆化 */
+ fun siftDown(it: Int) {
+ // Kotlin的函数参数不可变,因此创建临时变量
+ var i = it
+ while (true) {
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
+ val l = left(i)
+ val r = right(i)
+ var ma = i
+ if (l < size() && maxHeap[l] > maxHeap[ma]) ma = l
+ if (r < size() && maxHeap[r] > maxHeap[ma]) ma = r
+ // 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出
+ if (ma == i) break
+ // 交换两节点
+ swap(i, ma)
+ // 循环向下堆化
+ i = ma
+ }
+ }
+ ```
+
=== "Zig"
```zig title="my_heap.zig"
diff --git a/docs/chapter_heap/top_k.md b/docs/chapter_heap/top_k.md
index 0671ac155..ca4e54a67 100644
--- a/docs/chapter_heap/top_k.md
+++ b/docs/chapter_heap/top_k.md
@@ -411,6 +411,29 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="top_k.kt"
+ /* 基于堆查找数组中最大的 k 个元素 */
+ fun topKHeap(nums: IntArray, k: Int): Queue {
+ // 初始化小顶堆
+ val heap = PriorityQueue()
+ // 将数组的前 k 个元素入堆
+ for (i in 0.. heap.peek()) {
+ heap.poll()
+ heap.offer(nums[i])
+ }
+ }
+ return heap
+ }
+ ```
+
=== "Zig"
```zig title="top_k.zig"
diff --git a/docs/chapter_preface/suggestions.md b/docs/chapter_preface/suggestions.md
index 64c001e92..ee744419c 100644
--- a/docs/chapter_preface/suggestions.md
+++ b/docs/chapter_preface/suggestions.md
@@ -160,6 +160,19 @@ comments: true
*/
```
+=== "Kotlin"
+
+ ```kotlin title=""
+ /* 标题注释,用于标注函数、类、测试样例等 */
+
+ // 内容注释,用于详解代码
+
+ /**
+ * 多行
+ * 注释
+ */
+ ```
+
=== "Zig"
```zig title=""
diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md
index ed76ab8e5..bad38bad4 100755
--- a/docs/chapter_searching/binary_search.md
+++ b/docs/chapter_searching/binary_search.md
@@ -313,6 +313,29 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search.kt"
+ /* 二分查找(双闭区间) */
+ fun binarySearch(nums: IntArray, target: Int): Int {
+ // 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
+ var i = 0
+ var j = nums.size - 1
+ // 循环,当搜索区间为空时跳出(当 i > j 时为空)
+ while (i <= j) {
+ val m = i + (j - i) / 2 // 计算中点索引 m
+ if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
+ i = m + 1
+ else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
+ j = m - 1
+ else // 找到目标元素,返回其索引
+ return m
+ }
+ // 未找到目标元素,返回 -1
+ return -1
+ }
+ ```
+
=== "Zig"
```zig title="binary_search.zig"
@@ -612,6 +635,29 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search.kt"
+ /* 二分查找(左闭右开区间) */
+ fun binarySearchLCRO(nums: IntArray, target: Int): Int {
+ // 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
+ var i = 0
+ var j = nums.size
+ // 循环,当搜索区间为空时跳出(当 i = j 时为空)
+ while (i < j) {
+ val m = i + (j - i) / 2 // 计算中点索引 m
+ if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
+ i = m + 1
+ else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
+ j = m
+ else // 找到目标元素,返回其索引
+ return m
+ }
+ // 未找到目标元素,返回 -1
+ return -1
+ }
+ ```
+
=== "Zig"
```zig title="binary_search.zig"
diff --git a/docs/chapter_searching/binary_search_edge.md b/docs/chapter_searching/binary_search_edge.md
index a722cc647..adcb02c26 100644
--- a/docs/chapter_searching/binary_search_edge.md
+++ b/docs/chapter_searching/binary_search_edge.md
@@ -193,6 +193,22 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_edge.kt"
+ /* 二分查找最左一个 target */
+ fun binarySearchLeftEdge(nums: IntArray, target: Int): Int {
+ // 等价于查找 target 的插入点
+ val i = binarySearchInsertion(nums, target)
+ // 未找到 target ,返回 -1
+ if (i == nums.size || nums[i] != target) {
+ return -1
+ }
+ // 找到 target ,返回索引 i
+ return i
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_edge.zig"
@@ -418,6 +434,24 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_edge.kt"
+ /* 二分查找最右一个 target */
+ fun binarySearchRightEdge(nums: IntArray, target: Int): Int {
+ // 转化为查找最左一个 target + 1
+ val i = binarySearchInsertion(nums, target + 1)
+ // j 指向最右一个 target ,i 指向首个大于 target 的元素
+ val j = i - 1
+ // 未找到 target ,返回 -1
+ if (j == -1 || nums[j] != target) {
+ return -1
+ }
+ // 找到 target ,返回索引 j
+ return j
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_edge.zig"
diff --git a/docs/chapter_searching/binary_search_insertion.md b/docs/chapter_searching/binary_search_insertion.md
index 651e8754f..91dcf6c04 100644
--- a/docs/chapter_searching/binary_search_insertion.md
+++ b/docs/chapter_searching/binary_search_insertion.md
@@ -268,6 +268,28 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_insertion.kt"
+ /* 二分查找插入点(无重复元素) */
+ fun binarySearchInsertionSimple(nums: IntArray, target: Int): Int {
+ var i = 0
+ var j = nums.size - 1 // 初始化双闭区间 [0, n-1]
+ while (i <= j) {
+ val m = i + (j - i) / 2 // 计算中点索引 m
+ if (nums[m] < target) {
+ i = m + 1 // target 在区间 [m+1, j] 中
+ } else if (nums[m] > target) {
+ j = m - 1 // target 在区间 [i, m-1] 中
+ } else {
+ return m // 找到 target ,返回插入点 m
+ }
+ }
+ // 未找到 target ,返回插入点 i
+ return i
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_insertion.zig"
@@ -572,6 +594,28 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_insertion.kt"
+ /* 二分查找插入点(存在重复元素) */
+ fun binarySearchInsertion(nums: IntArray, target: Int): Int {
+ var i = 0
+ var j = nums.size - 1 // 初始化双闭区间 [0, n-1]
+ while (i <= j) {
+ val m = i + (j - i) / 2 // 计算中点索引 m
+ if (nums[m] < target) {
+ i = m + 1 // target 在区间 [m+1, j] 中
+ } else if (nums[m] > target) {
+ j = m - 1 // target 在区间 [i, m-1] 中
+ } else {
+ j = m - 1 // 首个小于 target 的元素在区间 [i, m-1] 中
+ }
+ }
+ // 返回插入点 i
+ return i
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_insertion.zig"
diff --git a/docs/chapter_searching/replace_linear_by_hashing.md b/docs/chapter_searching/replace_linear_by_hashing.md
index 190f79322..c179231e2 100755
--- a/docs/chapter_searching/replace_linear_by_hashing.md
+++ b/docs/chapter_searching/replace_linear_by_hashing.md
@@ -209,6 +209,22 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="two_sum.kt"
+ /* 方法一:暴力枚举 */
+ fun twoSumBruteForce(nums: IntArray, target: Int): IntArray {
+ val size = nums.size
+ // 两层循环,时间复杂度为 O(n^2)
+ for (i in 0..()
+ // 单层循环,时间复杂度为 O(n)
+ for (i in 0.. nums[j + 1]) {
+ // 交换 nums[j] 与 nums[j + 1]
+ nums[j] = nums[j+1].also { nums[j+1] = nums[j] }
+ }
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="bubble_sort.zig"
@@ -535,6 +553,27 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="bubble_sort.kt"
+ /* 冒泡排序(标志优化) */
+ fun bubbleSortWithFlag(nums: IntArray) {
+ // 外循环:未排序区间为 [0, i]
+ for (i in nums.size - 1 downTo 1) {
+ var flag = false // 初始化标志位
+ // 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
+ for (j in 0.. nums[j + 1]) {
+ // 交换 nums[j] 与 nums[j + 1]
+ nums[j] = nums[j + 1].also { nums[j] = nums[j + 1] }
+ flag = true // 记录交换元素
+ }
+ }
+ if (!flag) break // 此轮“冒泡”未交换任何元素,直接跳出
+ }
+ }
+ ```
+
=== "Zig"
```zig title="bubble_sort.zig"
diff --git a/docs/chapter_sorting/bucket_sort.md b/docs/chapter_sorting/bucket_sort.md
index 828deea8f..318e3738c 100644
--- a/docs/chapter_sorting/bucket_sort.md
+++ b/docs/chapter_sorting/bucket_sort.md
@@ -388,6 +388,39 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="bucket_sort.kt"
+ /* 桶排序 */
+ fun bucketSort(nums: FloatArray) {
+ // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素
+ val k = nums.size / 2
+ val buckets = ArrayList>()
+ for (i in 0.. nums[ma]) ma = l
+ if (r < n && nums[r] > nums[ma]) ma = r
+ // 若节点 i 最大或索引 l, r 越界,则无须继续堆化,跳出
+ if (ma == i) break
+ // 交换两节点
+ nums[i] = nums[ma].also { nums[ma] = nums[i] }
+ // 循环向下堆化
+ i = ma
+ }
+ }
+
+ /* 堆排序 */
+ fun heapSort(nums: IntArray) {
+ // 建堆操作:堆化除叶节点以外的其他所有节点
+ for (i in nums.size / 2 - 1 downTo 0) {
+ siftDown(nums, nums.size, i)
+ }
+ // 从堆中提取最大元素,循环 n-1 轮
+ for (i in nums.size - 1 downTo 1) {
+ // 交换根节点与最右叶节点(交换首元素与尾元素)
+ nums[0] = nums[i].also { nums[i] = nums[0] }
+ // 以根节点为起点,从顶至底进行堆化
+ siftDown(nums, i, 0)
+ }
+ }
+ ```
+
=== "Zig"
```zig title="heap_sort.zig"
diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md
index 145853d83..44c33c237 100755
--- a/docs/chapter_sorting/insertion_sort.md
+++ b/docs/chapter_sorting/insertion_sort.md
@@ -231,6 +231,25 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="insertion_sort.kt"
+ /* 插入排序 */
+ fun insertionSort(nums: IntArray) {
+ //外循环: 已排序元素为 1, 2, ..., n
+ for (i in nums.indices) {
+ val base = nums[i]
+ var j = i - 1
+ // 内循环: 将 base 插入到已排序部分的正确位置
+ while (j >= 0 && nums[j] > base) {
+ nums[j + 1] = nums[j] // 将 nums[j] 向右移动一位
+ j--
+ }
+ nums[j + 1] = base // 将 base 赋值到正确位置
+ }
+ }
+ ```
+
=== "Zig"
```zig title="insertion_sort.zig"
diff --git a/docs/chapter_sorting/merge_sort.md b/docs/chapter_sorting/merge_sort.md
index 6a2dcfa9d..542e7b875 100755
--- a/docs/chapter_sorting/merge_sort.md
+++ b/docs/chapter_sorting/merge_sort.md
@@ -582,6 +582,49 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="merge_sort.kt"
+ /* 合并左子数组和右子数组 */
+ fun merge(nums: IntArray, left: Int, mid: Int, right: Int) {
+ // 左子数组区间为 [left, mid], 右子数组区间为 [mid+1, right]
+ // 创建一个临时数组 tmp ,用于存放合并后的结果
+ val tmp = IntArray(right - left + 1)
+ // 初始化左子数组和右子数组的起始索引
+ var i = left
+ var j = mid + 1
+ var k = 0
+ // 当左右子数组都还有元素时,进行比较并将较小的元素复制到临时数组中
+ while (i <= mid && j <= right) {
+ if (nums[i] <= nums[j]) tmp[k++] = nums[i++]
+ else tmp[k++] = nums[j++]
+ }
+ // 将左子数组和右子数组的剩余元素复制到临时数组中
+ while (i <= mid) {
+ tmp[k++] = nums[i++]
+ }
+ while (j <= right) {
+ tmp[k++] = nums[j++]
+ }
+ // 将临时数组 tmp 中的元素复制回原数组 nums 的对应区间
+ for (l in tmp.indices) {
+ nums[left + l] = tmp[l]
+ }
+ }
+
+ /* 归并排序 */
+ fun mergeSort(nums: IntArray, left: Int, right: Int) {
+ // 终止条件
+ if (left >= right) return // 当子数组长度为 1 时终止递归
+ // 划分阶段
+ val mid = (left + right) / 2 // 计算中点
+ mergeSort(nums, left, mid) // 递归左子数组
+ mergeSort(nums, mid + 1, right) // 递归右子数组
+ // 合并阶段
+ merge(nums, left, mid, right)
+ }
+ ```
+
=== "Zig"
```zig title="merge_sort.zig"
diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md
index 6da5c2e74..a191de793 100755
--- a/docs/chapter_sorting/quick_sort.md
+++ b/docs/chapter_sorting/quick_sort.md
@@ -326,6 +326,31 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="quick_sort.kt"
+ /* 元素交换 */
+ fun swap(nums: IntArray, i: Int, j: Int) {
+ nums[i] = nums[j].also { nums[j] = nums[i] }
+ }
+
+ /* 哨兵划分 */
+ fun partition(nums: IntArray, left: Int, right: Int): Int {
+ // 以 nums[left] 为基准数
+ var i = left
+ var j = right
+ while (i < j) {
+ while (i < j && nums[j] >= nums[left])
+ j-- // 从右向左找首个小于基准数的元素
+ while (i < j && nums[i] <= nums[left])
+ i++ // 从左向右找首个大于基准数的元素
+ swap(nums, i, j) // 交换这两个元素
+ }
+ swap(nums, i, left) // 将基准数交换至两子数组的分界线
+ return i // 返回基准数的索引
+ }
+ ```
+
=== "Zig"
```zig title="quick_sort.zig"
@@ -569,6 +594,21 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="quick_sort.kt"
+ /* 快速排序 */
+ fun quickSort(nums: IntArray, left: Int, right: Int) {
+ // 子数组长度为 1 时终止递归
+ if (left >= right) return
+ // 哨兵划分
+ val pivot = partition(nums, left, right)
+ // 递归左子数组、右子数组
+ quickSort(nums, left, pivot - 1)
+ quickSort(nums, pivot + 1, right)
+ }
+ ```
+
=== "Zig"
```zig title="quick_sort.zig"
@@ -1001,6 +1041,38 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="quick_sort.kt"
+ /* 选取三个候选元素的中位数 */
+ fun medianThree(nums: IntArray, left: Int, mid: Int, right: Int): Int {
+ val l = nums[left]
+ val m = nums[mid]
+ val r = nums[right]
+ if ((m in l..r) || (m in r..l))
+ return mid // m 在 l 和 r 之间
+ if ((l in m..r) || (l in r..m))
+ return left // l 在 m 和 r 之间
+ return right
+ }
+
+ /* 哨兵划分 */
+ fun partition(nums: IntArray, left: Int, right: Int): Int {
+ // 以 nums[left] 为基准数
+ var i = left
+ var j = right
+ while (i < j) {
+ while (i < j && nums[j] >= nums[left])
+ j-- // 从右向左找首个小于基准数的元素
+ while (i < j && nums[i] <= nums[left])
+ i++ // 从左向右找首个大于基准数的元素
+ swap(nums, i, j) // 交换这两个元素
+ }
+ swap(nums, i, left) // 将基准数交换至两子数组的分界线
+ return i // 返回基准数的索引
+ }
+ ```
+
=== "Zig"
```zig title="quick_sort.zig"
@@ -1277,6 +1349,21 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="quick_sort.kt"
+ /* 快速排序 */
+ fun quickSort(nums: IntArray, left: Int, right: Int) {
+ // 子数组长度为 1 时终止递归
+ if (left >= right) return
+ // 哨兵划分
+ val pivot = partition(nums, left, right)
+ // 递归左子数组、右子数组
+ quickSort(nums, left, pivot - 1)
+ quickSort(nums, pivot + 1, right)
+ }
+ ```
+
=== "Zig"
```zig title="quick_sort.zig"
diff --git a/docs/chapter_sorting/radix_sort.md b/docs/chapter_sorting/radix_sort.md
index 18a5a792f..53e534291 100644
--- a/docs/chapter_sorting/radix_sort.md
+++ b/docs/chapter_sorting/radix_sort.md
@@ -619,6 +619,59 @@ $$
}
```
+=== "Kotlin"
+
+ ```kotlin title="radix_sort.kt"
+ /* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */
+ fun digit(num: Int, exp: Int): Int {
+ // 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算
+ return (num / exp) % 10
+ }
+
+ /* 计数排序(根据 nums 第 k 位排序) */
+ fun countingSortDigit(nums: IntArray, exp: Int) {
+ // 十进制的位范围为 0~9 ,因此需要长度为 10 的桶数组
+ val counter = IntArray(10)
+ val n = nums.size
+ // 统计 0~9 各数字的出现次数
+ for (i in 0.. m) m = num
+ var exp = 1
+ // 按照从低位到高位的顺序遍历
+ while (exp <= m) {
+ // 对数组元素的第 k 位执行计数排序
+ // k = 1 -> exp = 1
+ // k = 2 -> exp = 10
+ // 即 exp = 10^(k-1)
+ countingSortDigit(nums, exp)
+ exp *= 10
+ }
+ }
+ ```
+
=== "Zig"
```zig title="radix_sort.zig"
diff --git a/docs/chapter_sorting/selection_sort.md b/docs/chapter_sorting/selection_sort.md
index 3e3702fb4..5a35ac2e9 100644
--- a/docs/chapter_sorting/selection_sort.md
+++ b/docs/chapter_sorting/selection_sort.md
@@ -281,6 +281,25 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="selection_sort.kt"
+ /* 选择排序 */
+ fun selectionSort(nums: IntArray) {
+ val n = nums.size
+ // 外循环:未排序区间为 [i, n-1]
+ for (i in 0..()
+
+ /* 获取栈的长度 */
+ fun size(): Int {
+ return stack.size
+ }
+
+ /* 判断栈是否为空 */
+ fun isEmpty(): Boolean {
+ return size() == 0
+ }
+
+ /* 入栈 */
+ fun push(num: Int) {
+ stack.add(num)
+ }
+
+ /* 出栈 */
+ fun pop(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return stack.removeAt(size() - 1)
+ }
+
+ /* 访问栈顶元素 */
+ fun peek(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return stack[size() - 1]
+ }
+
+ /* 将 List 转化为 Array 并返回 */
+ fun toArray(): Array {
+ return stack.toArray()
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_stack.zig"
diff --git a/docs/chapter_tree/array_representation_of_tree.md b/docs/chapter_tree/array_representation_of_tree.md
index 4515667c1..89b3d909b 100644
--- a/docs/chapter_tree/array_representation_of_tree.md
+++ b/docs/chapter_tree/array_representation_of_tree.md
@@ -120,6 +120,12 @@ comments: true
int tree[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -1155,6 +1161,85 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="array_binary_tree.kt"
+ /* 数组表示下的二叉树类 */
+ class ArrayBinaryTree(val tree: List) {
+ /* 列表容量 */
+ fun size(): Int {
+ return tree.size
+ }
+
+ /* 获取索引为 i 节点的值 */
+ fun value(i: Int): Int? {
+ // 若索引越界,则返回 null ,代表空位
+ if (i < 0 || i >= size()) return null
+ return tree[i]
+ }
+
+ /* 获取索引为 i 节点的左子节点的索引 */
+ fun left(i: Int): Int {
+ return 2 * i + 1
+ }
+
+ /* 获取索引为 i 节点的右子节点的索引 */
+ fun right(i: Int): Int {
+ return 2 * i + 2
+ }
+
+ /* 获取索引为 i 节点的父节点的索引 */
+ fun parent(i: Int): Int {
+ return (i - 1) / 2
+ }
+
+ /* 层序遍历 */
+ fun levelOrder(): List {
+ val res = ArrayList()
+ // 直接遍历数组
+ for (i in 0..) {
+ // 若为空位,则返回
+ if (value(i) == null) return
+ // 前序遍历
+ if ("pre" == order) res.add(value(i))
+ dfs(left(i), order, res)
+ // 中序遍历
+ if ("in" == order) res.add(value(i))
+ dfs(right(i), order, res)
+ // 后序遍历
+ if ("post" == order) res.add(value(i))
+ }
+
+ /* 前序遍历 */
+ fun preOrder(): List {
+ val res = ArrayList()
+ dfs(0, "pre", res)
+ return res
+ }
+
+ /* 中序遍历 */
+ fun inOrder(): List {
+ val res = ArrayList()
+ dfs(0, "in", res)
+ return res
+ }
+
+ /* 后序遍历 */
+ fun postOrder(): List {
+ val res = ArrayList()
+ dfs(0, "post", res)
+ return res
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_binary_tree.zig"
diff --git a/docs/chapter_tree/avl_tree.md b/docs/chapter_tree/avl_tree.md
index 2e95f1649..06d26d2d1 100644
--- a/docs/chapter_tree/avl_tree.md
+++ b/docs/chapter_tree/avl_tree.md
@@ -208,6 +208,12 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -419,6 +425,22 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 获取节点高度 */
+ fun height(node: TreeNode?): Int {
+ // 空节点高度为 -1 ,叶节点高度为 0
+ return node?.height ?: -1
+ }
+
+ /* 更新节点高度 */
+ fun updateHeight(node: TreeNode?) {
+ // 节点高度等于最高子树高度 + 1
+ node?.height = (max(height(node?.left).toDouble(), height(node?.right).toDouble()) + 1).toInt()
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -582,6 +604,18 @@ AVL 树既是二叉搜索树,也是平衡二叉树,同时满足这两类二
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 获取平衡因子 */
+ fun balanceFactor(node: TreeNode?): Int {
+ // 空节点平衡因子为 0
+ if (node == null) return 0
+ // 节点平衡因子 = 左子树高度 - 右子树高度
+ return height(node.left) - height(node.right)
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -833,6 +867,24 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 右旋操作 */
+ fun rightRotate(node: TreeNode?): TreeNode {
+ val child = node!!.left
+ val grandChild = child!!.right
+ // 以 child 为原点,将 node 向右旋转
+ child.right = node
+ node.left = grandChild
+ // 更新节点高度
+ updateHeight(node)
+ updateHeight(child)
+ // 返回旋转后子树的根节点
+ return child
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -1070,6 +1122,24 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 左旋操作 */
+ fun leftRotate(node: TreeNode?): TreeNode {
+ val child = node!!.right
+ val grandChild = child!!.left
+ // 以 child 为原点,将 node 向左旋转
+ child.left = node
+ node.right = grandChild
+ // 更新节点高度
+ updateHeight(node)
+ updateHeight(child)
+ // 返回旋转后子树的根节点
+ return child
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -1504,6 +1574,40 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 执行旋转操作,使该子树重新恢复平衡 */
+ fun rotate(node: TreeNode): TreeNode {
+ // 获取节点 node 的平衡因子
+ val balanceFactor = balanceFactor(node)
+ // 左偏树
+ if (balanceFactor > 1) {
+ if (balanceFactor(node.left) >= 0) {
+ // 右旋
+ return rightRotate(node)
+ } else {
+ // 先左旋后右旋
+ node.left = leftRotate(node.left)
+ return rightRotate(node)
+ }
+ }
+ // 右偏树
+ if (balanceFactor < -1) {
+ if (balanceFactor(node.right) <= 0) {
+ // 左旋
+ return leftRotate(node)
+ } else {
+ // 先右旋后左旋
+ node.right = rightRotate(node.right)
+ return leftRotate(node)
+ }
+ }
+ // 平衡树,无须旋转,直接返回
+ return node
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -1861,6 +1965,32 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 插入节点 */
+ fun insert(value: Int) {
+ root = insertHelper(root, value)
+ }
+
+ /* 递归插入节点(辅助方法) */
+ fun insertHelper(n: TreeNode?, value: Int): TreeNode {
+ if (n == null)
+ 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 // 重复节点不插入,直接返回
+
+ updateHeight(node) // 更新节点高度
+ /* 2. 执行旋转操作,使该子树重新恢复平衡 */
+ node = rotate(node)
+ // 返回子树的根节点
+ return node
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
@@ -2408,6 +2538,44 @@ AVL 树的节点插入操作与二叉搜索树在主体上类似。唯一的区
}
```
+=== "Kotlin"
+
+ ```kotlin title="avl_tree.kt"
+ /* 删除节点 */
+ fun remove(value: Int) {
+ root = removeHelper(root, value)
+ }
+
+ /* 递归删除节点(辅助方法) */
+ 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)
+ else {
+ if (node.left == null || node.right == null) {
+ val child = if (node.left != null) node.left else node.right
+ // 子节点数量 = 0 ,直接删除 node 并返回
+ if (child == null) return null
+ else node = child
+ } else {
+ // 子节点数量 = 2 ,则将中序遍历的下个节点删除,并用该节点替换当前节点
+ var temp = node.right
+ while (temp!!.left != null) {
+ temp = temp.left
+ }
+ node.right = removeHelper(node.right, temp.value)
+ node.value = temp.value
+ }
+ }
+ updateHeight(node) // 更新节点高度
+ /* 2. 执行旋转操作,使该子树重新恢复平衡 */
+ node = rotate(node)
+ // 返回子树的根节点
+ return node
+ }
+ ```
+
=== "Zig"
```zig title="avl_tree.zig"
diff --git a/docs/chapter_tree/binary_search_tree.md b/docs/chapter_tree/binary_search_tree.md
index 280235bd1..b39545533 100755
--- a/docs/chapter_tree/binary_search_tree.md
+++ b/docs/chapter_tree/binary_search_tree.md
@@ -290,6 +290,26 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_tree.kt"
+ /* 查找节点 */
+ fun search(num: Int): TreeNode? {
+ var cur = root
+ // 循环查找,越过叶节点后跳出
+ while (cur != null) {
+ // 目标节点在 cur 的右子树中
+ cur = if (cur.value < num) cur.right
+ // 目标节点在 cur 的左子树中
+ else if (cur.value > num) cur.left
+ // 找到目标节点,跳出循环
+ else break
+ }
+ // 返回目标节点
+ return cur
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_tree.zig"
@@ -707,6 +727,35 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_tree.kt"
+ /* 插入节点 */
+ fun insert(num: Int) {
+ // 若树为空,则初始化根节点
+ if (root == null) {
+ root = TreeNode(num)
+ return
+ }
+ var cur = root
+ var pre: TreeNode? = null
+ // 循环查找,越过叶节点后跳出
+ while (cur != null) {
+ // 找到重复节点,直接返回
+ if (cur.value == num) return
+ pre = cur
+ // 插入位置在 cur 的右子树中
+ cur = if (cur.value < num) cur.right
+ // 插入位置在 cur 的左子树中
+ else cur.left
+ }
+ // 插入节点
+ val node = TreeNode(num)
+ if (pre?.value!! < num) pre.right = node
+ else pre.left = node
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_tree.zig"
@@ -1415,6 +1464,54 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_search_tree.kt"
+ /* 删除节点 */
+ fun remove(num: Int) {
+ // 若树为空,直接提前返回
+ if (root == null) return
+ var cur = root
+ var pre: TreeNode? = null
+ // 循环查找,越过叶节点后跳出
+ while (cur != null) {
+ // 找到待删除节点,跳出循环
+ if (cur.value == num) break
+ pre = cur
+ // 待删除节点在 cur 的右子树中
+ cur = if (cur.value < num) cur.right
+ // 待删除节点在 cur 的左子树中
+ else cur.left
+ }
+ // 若无待删除节点,则直接返回
+ 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
+ // 删除节点 cur
+ if (cur != root) {
+ if (pre!!.left == cur) pre.left = child
+ else pre.right = child
+ } else {
+ // 若删除节点为根节点,则重新指定根节点
+ root = child
+ }
+ // 子节点数量 = 2
+ } else {
+ // 获取中序遍历中 cur 的下一个节点
+ var tmp = cur.right
+ while (tmp!!.left != null) {
+ tmp = tmp.left
+ }
+ // 递归删除节点 tmp
+ remove(tmp.value)
+ // 用 tmp 覆盖 cur
+ cur.value = tmp.value
+ }
+ }
+ ```
+
=== "Zig"
```zig title="binary_search_tree.zig"
diff --git a/docs/chapter_tree/binary_tree.md b/docs/chapter_tree/binary_tree.md
index 5a4544484..2fc54475f 100644
--- a/docs/chapter_tree/binary_tree.md
+++ b/docs/chapter_tree/binary_tree.md
@@ -180,6 +180,12 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -405,6 +411,12 @@ comments: true
n2->right = n5;
```
+=== "Kotlin"
+
+ ```kotlin title="binary_tree.kt"
+
+ ```
+
=== "Zig"
```zig title="binary_tree.zig"
@@ -553,6 +565,12 @@ comments: true
n1->left = n2;
```
+=== "Kotlin"
+
+ ```kotlin title="binary_tree.kt"
+
+ ```
+
=== "Zig"
```zig title="binary_tree.zig"
diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md
index 0e924aa22..057c0d659 100755
--- a/docs/chapter_tree/binary_tree_traversal.md
+++ b/docs/chapter_tree/binary_tree_traversal.md
@@ -293,6 +293,27 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_tree_bfs.kt"
+ /* 层序遍历 */
+ fun levelOrder(root: TreeNode?): MutableList {
+ // 初始化队列,加入根节点
+ val queue = LinkedList()
+ queue.add(root)
+ // 初始化一个列表,用于保存遍历序列
+ val list = ArrayList()
+ 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) // 右子节点入队
+ }
+ return list
+ }
+ ```
+
=== "Zig"
```zig title="binary_tree_bfs.zig"
@@ -729,6 +750,37 @@ comments: true
}
```
+=== "Kotlin"
+
+ ```kotlin title="binary_tree_dfs.kt"
+ /* 前序遍历 */
+ fun preOrder(root: TreeNode?) {
+ if (root == null) return
+ // 访问优先级:根节点 -> 左子树 -> 右子树
+ list.add(root.value)
+ preOrder(root.left)
+ preOrder(root.right)
+ }
+
+ /* 中序遍历 */
+ fun inOrder(root: TreeNode?) {
+ if (root == null) return
+ // 访问优先级:左子树 -> 根节点 -> 右子树
+ inOrder(root.left)
+ list.add(root.value)
+ inOrder(root.right)
+ }
+
+ /* 后序遍历 */
+ fun postOrder(root: TreeNode?) {
+ if (root == null) return
+ // 访问优先级:左子树 -> 右子树 -> 根节点
+ postOrder(root.left)
+ postOrder(root.right)
+ list.add(root.value)
+ }
+ ```
+
=== "Zig"
```zig title="binary_tree_dfs.zig"
diff --git a/en/docs/chapter_array_and_linkedlist/array.md b/en/docs/chapter_array_and_linkedlist/array.md
index b8cc64c99..add27422b 100755
--- a/en/docs/chapter_array_and_linkedlist/array.md
+++ b/en/docs/chapter_array_and_linkedlist/array.md
@@ -111,6 +111,12 @@ Arrays can be initialized in two ways depending on the needs: either without ini
int nums[5] = { 1, 3, 2, 5, 4 };
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -274,6 +280,19 @@ Accessing elements in an array is highly efficient, allowing us to randomly acce
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 随机访问元素 */
+ fun randomAccess(nums: IntArray): Int {
+ // 在区间 [0, nums.size) 中随机抽取一个数字
+ val randomIndex = ThreadLocalRandom.current().nextInt(0, nums.size)
+ // 获取并返回随机元素
+ val randomNum = nums[randomIndex]
+ return randomNum
+ }
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -454,6 +473,20 @@ It's important to note that due to the fixed length of an array, inserting an el
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 在数组的索引 index 处插入元素 num */
+ fun insert(nums: IntArray, num: Int, index: Int) {
+ // 把索引 index 以及之后的所有元素向后移动一位
+ for (i in nums.size - 1 downTo index + 1) {
+ nums[i] = nums[i - 1]
+ }
+ // 将 num 赋给 index 处的元素
+ nums[index] = num
+ }
+ ```
+
=== "Zig"
```zig title="array.zig"
@@ -615,6 +648,18 @@ Please note that after deletion, the former last element becomes "meaningless,"
}
```
+=== "Kotlin"
+
+ ```kotlin title="array.kt"
+ /* 删除索引 index 处的元素 */
+ fun remove(nums: IntArray, index: Int) {
+ // 把索引 index 之后的所有元素向前移动一位
+ for (i in index..next = n4;
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -529,6 +541,17 @@ By comparison, inserting an element into an array has a time complexity of $O(n)
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 在链表的节点 n0 之后插入节点p */
+ fun insert(n0: ListNode?, p: ListNode?) {
+ val n1 = n0?.next
+ p?.next = n1
+ n0?.next = p
+ }
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -718,6 +741,17 @@ It's important to note that even though node `P` continues to point to `n1` afte
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 删除链表的节点 n0 之后的首个节点 */
+ fun remove(n0: ListNode?) {
+ val p = n0?.next
+ val n1 = p?.next
+ n0?.next = n1
+ }
+ ```
+
=== "Zig"
```zig title="linked_list.zig"
@@ -898,6 +932,19 @@ It's important to note that even though node `P` continues to point to `n1` afte
}
```
+=== "Kotlin"
+
+ ```kotlin title="linked_list.kt"
+ /* 访问链表中索引为 index 的节点 */
+ fun access(head: ListNode?, index: Int): ListNode? {
+ var h = head
+ for (i in 0..= size)
+ throw IndexOutOfBoundsException()
+ return arr[index]
+ }
+
+ /* 更新元素 */
+ fun set(index: Int, num: Int) {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ arr[index] = num
+ }
+
+ /* 在尾部添加元素 */
+ fun add(num: Int) {
+ // 元素数量超出容量时,触发扩容机制
+ if (size == capacity())
+ extendCapacity()
+ arr[size] = num
+ // 更新元素数量
+ size++
+ }
+
+ /* 在中间插入元素 */
+ fun insert(index: Int, num: Int) {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ // 元素数量超出容量时,触发扩容机制
+ if (size == capacity())
+ extendCapacity()
+ // 将索引 index 以及之后的元素都向后移动一位
+ for (j in size - 1 downTo index)
+ arr[j + 1] = arr[j]
+ arr[index] = num
+ // 更新元素数量
+ size++
+ }
+
+ /* 删除元素 */
+ fun remove(index: Int): Int {
+ if (index < 0 || index >= size)
+ throw IndexOutOfBoundsException("索引越界")
+ val num: Int = arr[index]
+ // 将将索引 index 之后的元素都向前移动一位
+ for (j in index..()
+ var res = 0
+ // 递: 递归调用
+ for (i in n downTo 0) {
+ stack.push(i)
+ }
+ // 归: 返回结果
+ while (stack.isNotEmpty()) {
+ // 通过“出栈操作”模拟“归”
+ res += stack.pop()
+ }
+ // res = 1+2+3+...+n
+ return res
+ }
+ ```
+
=== "Zig"
```zig title="recursion.zig"
diff --git a/en/docs/chapter_computational_complexity/space_complexity.md b/en/docs/chapter_computational_complexity/space_complexity.md
index baeb34b63..86b406c3e 100644
--- a/en/docs/chapter_computational_complexity/space_complexity.md
+++ b/en/docs/chapter_computational_complexity/space_complexity.md
@@ -316,6 +316,12 @@ The relevant code is as follows:
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -462,6 +468,12 @@ Consider the following code, the term "worst-case" in worst-case space complexit
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -482,9 +494,10 @@ Consider the following code, the term "worst-case" in worst-case space complexit
for _ in range(n):
function()
- def recur(n: int) -> int:
+ def recur(n: int):
"""Recursion O(n)"""""
- if n == 1: return
+ if n == 1:
+ return
return recur(n - 1)
```
@@ -699,6 +712,12 @@ Consider the following code, the term "worst-case" in worst-case space complexit
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -725,7 +744,7 @@ $$
Figure 2-16 Common Types of Space Complexity
-### 1. Constant Order $O(1)$
+### 1. Constant Order $O(1)$ {data-toc-label="Constant Order"}
Constant order is common in constants, variables, objects that are independent of the size of input data $n$.
@@ -1031,6 +1050,33 @@ Note that memory occupied by initializing variables or calling functions in a lo
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 函数 */
+ fun function(): Int {
+ // 执行某些操作
+ return 0
+ }
+
+ /* 常数阶 */
+ fun constant(n: Int) {
+ // 常量、变量、对象占用 O(1) 空间
+ val a = 0
+ var b = 0
+ val nums = Array(10000) { 0 }
+ val node = ListNode(0)
+ // 循环中的变量占用 O(1) 空间
+ for (i in 0..
-### 2. Linear Order $O(n)$
+### 2. Linear Order $O(n)$ {data-toc-label="Linear Order"}
Linear order is common in arrays, linked lists, stacks, queues, etc., where the number of elements is proportional to $n$:
@@ -1307,6 +1353,26 @@ Linear order is common in arrays, linked lists, stacks, queues, etc., where the
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 线性阶 */
+ fun linear(n: Int) {
+ // 长度为 n 的数组占用 O(n) 空间
+ val nums = Array(n) { 0 }
+ // 长度为 n 的列表占用 O(n) 空间
+ val nodes = mutableListOf()
+ for (i in 0..()
+ for (i in 0.. Figure 2-17 Recursive Function Generating Linear Order Space Complexity
-### 3. Quadratic Order $O(n^2)$
+### 3. Quadratic Order $O(n^2)$ {data-toc-label="Quadratic Order"}
Quadratic order is common in matrices and graphs, where the number of elements is quadratic to $n$:
@@ -1686,6 +1764,25 @@ Quadratic order is common in matrices and graphs, where the number of elements i
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 平方阶 */
+ fun quadratic(n: Int) {
+ // 矩阵占用 O(n^2) 空间
+ val numMatrix: Array?> = arrayOfNulls(n)
+ // 二维列表占用 O(n^2) 空间
+ val numList: MutableList> = arrayListOf()
+ for (i in 0..()
+ for (j in 0.. Figure 2-18 Recursive Function Generating Quadratic Order Space Complexity
-### 4. Exponential Order $O(2^n)$
+### 4. Exponential Order $O(2^n)$ {data-toc-label="Exponential Order"}
Exponential order is common in binary trees. Observe the below image, a "full binary tree" with $n$ levels has $2^n - 1$ nodes, occupying $O(2^n)$ space:
@@ -2039,6 +2150,20 @@ Exponential order is common in binary trees. Observe the below image, a "full bi
}
```
+=== "Kotlin"
+
+ ```kotlin title="space_complexity.kt"
+ /* 指数阶(建立满二叉树) */
+ fun buildTree(n: Int): TreeNode? {
+ if (n == 0)
+ return null
+ val root = TreeNode(0)
+ root.left = buildTree(n - 1)
+ root.right = buildTree(n - 1)
+ return root
+ }
+ ```
+
=== "Zig"
```zig title="space_complexity.zig"
@@ -2062,7 +2187,7 @@ Exponential order is common in binary trees. Observe the below image, a "full bi
Figure 2-19 Full Binary Tree Generating Exponential Order Space Complexity
-### 5. Logarithmic Order $O(\log n)$
+### 5. Logarithmic Order $O(\log n)$ {data-toc-label="Logarithmic Order"}
Logarithmic order is common in divide-and-conquer algorithms. For example, in merge sort, an array of length $n$ is recursively divided in half each round, forming a recursion tree of height $\log n$, using $O(\log n)$ stack frame space.
diff --git a/en/docs/chapter_computational_complexity/time_complexity.md b/en/docs/chapter_computational_complexity/time_complexity.md
index c97d826a7..a1b996160 100644
--- a/en/docs/chapter_computational_complexity/time_complexity.md
+++ b/en/docs/chapter_computational_complexity/time_complexity.md
@@ -175,6 +175,12 @@ For example, consider the following code with an input size of $n$:
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -433,6 +439,12 @@ Let's understand this concept of "time growth trend" with an example. Assume the
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -629,6 +641,12 @@ Consider a function with an input size of $n$:
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -886,6 +904,12 @@ Given a function, we can use these techniques to count operations:
}
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
@@ -952,7 +976,7 @@ $$
Figure 2-9 Common Types of Time Complexity
-### 1. Constant Order $O(1)$
+### 1. Constant Order $O(1)$ {data-toc-label="Constant Order"}
Constant order means the number of operations is independent of the input data size $n$. In the following function, although the number of operations `size` might be large, the time complexity remains $O(1)$ as it's unrelated to $n$:
@@ -1103,6 +1127,19 @@ Constant order means the number of operations is independent of the input data s
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 常数阶 */
+ fun constant(n: Int): Int {
+ var count = 0
+ val size = 10_0000
+ for (i in 0..
-### 2. Linear Order $O(n)$
+### 2. Linear Order $O(n)$ {data-toc-label="Linear Order"}
Linear order indicates the number of operations grows linearly with the input data size $n$. Linear order commonly appears in single-loop structures:
@@ -1262,6 +1299,19 @@ Linear order indicates the number of operations grows linearly with the input da
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 线性阶 */
+ fun linear(n: Int): Int {
+ var count = 0
+ // 循环次数与数组长度成正比
+ for (i in 0.. nums[j + 1]) {
+ // 交换 nums[j] 与 nums[j + 1]
+ nums[j] = nums[j + 1].also { nums[j + 1] = nums[j] }
+ count += 3 // 元素交换包含 3 个单元操作
+ }
+ }
+ }
+ return count
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -1942,7 +2043,7 @@ For instance, in bubble sort, the outer loop runs $n - 1$ times, and the inner l
-### 4. Exponential Order $O(2^n)$
+### 4. Exponential Order $O(2^n)$ {data-toc-label="Exponential Order"}
Biological "cell division" is a classic example of exponential order growth: starting with one cell, it becomes two after one division, four after two divisions, and so on, resulting in $2^n$ cells after $n$ divisions.
@@ -2149,6 +2250,25 @@ The following image and code simulate the cell division process, with a time com
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 指数阶(循环实现) */
+ fun exponential(n: Int): Int {
+ var count = 0
+ // 细胞每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1)
+ var base = 1
+ for (i in 0.. 1) {
+ n1 /= 2
+ count++
+ }
+ return count
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -2622,6 +2769,17 @@ Like exponential order, logarithmic order also frequently appears in recursive f
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 对数阶(递归实现) */
+ fun logRecur(n: Int): Int {
+ if (n <= 1)
+ return 0
+ return logRecur(n / 2) + 1
+ }
+ ```
+
=== "Zig"
```zig title="time_complexity.zig"
@@ -2649,7 +2807,7 @@ Logarithmic order is typical in algorithms based on the divide-and-conquer strat
This means the base $m$ can be changed without affecting the complexity. Therefore, we often omit the base $m$ and simply denote logarithmic order as $O(\log n)$.
-### 6. Linear-Logarithmic Order $O(n \log n)$
+### 6. Linear-Logarithmic Order $O(n \log n)$ {data-toc-label="Linear-Logarithmic Order"}
Linear-logarithmic order often appears in nested loops, with the complexities of the two loops being $O(\log n)$ and $O(n)$ respectively. The related code is as follows:
@@ -2815,6 +2973,21 @@ Linear-logarithmic order often appears in nested loops, with the complexities of
}
```
+=== "Kotlin"
+
+ ```kotlin title="time_complexity.kt"
+ /* 线性对数阶 */
+ fun linearLogRecur(n: Int): Int {
+ if (n <= 1)
+ return 1
+ var count = linearLogRecur(n / 2) + linearLogRecur(n / 2)
+ for (i in 0.. {
+ val nums = IntArray(n)
+ // 生成数组 nums = { 1, 2, 3, ..., n }
+ for (i in 0.. int[]
+ val res = arrayOfNulls(n)
+ for (i in 0..): Int {
+ for (i in nums.indices) {
+ // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1)
+ // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n)
+ if (nums[i] == 1)
+ return i
+ }
+ return -1
+ }
+ ```
+
=== "Zig"
```zig title="worst_best_time_complexity.zig"
diff --git a/en/docs/chapter_data_structure/basic_data_types.md b/en/docs/chapter_data_structure/basic_data_types.md
index f1707fa91..ad9577863 100644
--- a/en/docs/chapter_data_structure/basic_data_types.md
+++ b/en/docs/chapter_data_structure/basic_data_types.md
@@ -161,6 +161,12 @@ In other words, **basic data types provide the "content type" of data, while dat
bool bools[10];
```
+=== "Kotlin"
+
+ ```kotlin title=""
+
+ ```
+
=== "Zig"
```zig title=""
diff --git a/en/docs/chapter_hashing/hash_algorithm.md b/en/docs/chapter_hashing/hash_algorithm.md
index 9cb093294..bdfa6a859 100644
--- a/en/docs/chapter_hashing/hash_algorithm.md
+++ b/en/docs/chapter_hashing/hash_algorithm.md
@@ -554,6 +554,46 @@ The design of hash algorithms is a complex issue that requires consideration of
}
```
+=== "Kotlin"
+
+ ```kotlin title="simple_hash.kt"
+ /* 加法哈希 */
+ fun addHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = (hash + c.code) % MODULUS
+ }
+ return hash.toInt()
+ }
+
+ /* 乘法哈希 */
+ fun mulHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = (31 * hash + c.code) % MODULUS
+ }
+ return hash.toInt()
+ }
+
+ /* 异或哈希 */
+ fun xorHash(key: String): Int {
+ var hash = 0
+ for (c in key.toCharArray()) {
+ hash = hash xor c.code
+ }
+ return hash and MODULUS
+ }
+
+ /* 旋转哈希 */
+ fun rotHash(key: String): Int {
+ var hash = 0L
+ for (c in key.toCharArray()) {
+ hash = ((hash shl 4) xor (hash shr 28) xor c.code.toLong()) % MODULUS
+ }
+ return hash.toInt()
+ }
+ ```
+
=== "Zig"
```zig title="simple_hash.zig"
@@ -868,6 +908,12 @@ We know that the keys in a hash table can be of various data types such as integ
// C does not provide built-in hash code functions
```
+=== "Kotlin"
+
+ ```kotlin title="built_in_hash.kt"
+
+ ```
+
=== "Zig"
```zig title="built_in_hash.zig"
diff --git a/en/docs/chapter_hashing/hash_collision.md b/en/docs/chapter_hashing/hash_collision.md
index e44574e6f..4b4ce91c2 100644
--- a/en/docs/chapter_hashing/hash_collision.md
+++ b/en/docs/chapter_hashing/hash_collision.md
@@ -1311,6 +1311,121 @@ The code below provides a simple implementation of a separate chaining hash tabl
}
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map_chaining.kt"
+ /* 链式地址哈希表 */
+ class HashMapChaining() {
+ var size: Int // 键值对数量
+ var capacity: Int // 哈希表容量
+ val loadThres: Double // 触发扩容的负载因子阈值
+ val extendRatio: Int // 扩容倍数
+ var buckets: MutableList> // 桶数组
+
+ /* 构造方法 */
+ init {
+ size = 0
+ capacity = 4
+ loadThres = 2.0 / 3.0
+ extendRatio = 2
+ buckets = ArrayList(capacity)
+ for (i in 0.. loadThres) {
+ extend()
+ }
+ val index = hashFunc(key)
+ val bucket = buckets[index]
+ // 遍历桶,若遇到指定 key ,则更新对应 val 并返回
+ for (pair in bucket) {
+ if (pair.key == key) {
+ pair.value = value
+ return
+ }
+ }
+ // 若无该 key ,则将键值对添加至尾部
+ val pair = Pair(key, value)
+ bucket.add(pair)
+ size++
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ val bucket = buckets[index]
+ // 遍历桶,从中删除键值对
+ for (pair in bucket) {
+ if (pair.key == key) {
+ bucket.remove(pair)
+ size--
+ break
+ }
+ }
+ }
+
+ /* 扩容哈希表 */
+ fun extend() {
+ // 暂存原哈希表
+ val bucketsTmp = buckets
+ // 初始化扩容后的新哈希表
+ capacity *= extendRatio
+ // mutablelist 无固定大小
+ buckets = mutableListOf()
+ for (i in 0..()
+ for (pair in bucket) {
+ val k = pair.key
+ val v = pair.value
+ res.add("$k -> $v")
+ }
+ println(res)
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="hash_map_chaining.zig"
@@ -2831,6 +2946,132 @@ The code below implements an open addressing (linear probing) hash table with la
}
```
+=== "Kotlin"
+
+ ```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 // 桶数组
+ private val TOMBSTONE = Pair(-1, "-1") // 删除标记
+
+ /* 构造方法 */
+ init {
+ buckets = arrayOfNulls(capacity)
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ return key % capacity
+ }
+
+ /* 负载因子 */
+ fun loadFactor(): Double {
+ return (size / capacity).toDouble()
+ }
+
+ /* 搜索 key 对应的桶索引 */
+ fun findBucket(key: Int): Int {
+ var index = hashFunc(key)
+ var firstTombstone = -1
+ // 线性探测,当遇到空桶时跳出
+ while (buckets[index] != null) {
+ // 若遇到 key ,返回对应的桶索引
+ if (buckets[index]?.key == key) {
+ // 若之前遇到了删除标记,则将键值对移动至该索引处
+ if (firstTombstone != -1) {
+ buckets[firstTombstone] = buckets[index]
+ buckets[index] = TOMBSTONE
+ return firstTombstone // 返回移动后的桶索引
+ }
+ return index // 返回桶索引
+ }
+ // 记录遇到的首个删除标记
+ if (firstTombstone == -1 && buckets[index] == TOMBSTONE) {
+ firstTombstone = index
+ }
+ // 计算桶索引,越过尾部则返回头部
+ index = (index + 1) % capacity
+ }
+ // 若 key 不存在,则返回添加点的索引
+ return if (firstTombstone == -1) index else firstTombstone
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则返回对应 val
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ return buckets[index]?.value
+ }
+ // 若键值对不存在,则返回 null
+ return null
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ // 当负载因子超过阈值时,执行扩容
+ if (loadFactor() > loadThres) {
+ extend()
+ }
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则覆盖 val 并返回
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ buckets[index]!!.value = value
+ return
+ }
+ // 若键值对不存在,则添加该键值对
+ buckets[index] = Pair(key, value)
+ size++
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ // 搜索 key 对应的桶索引
+ val index = findBucket(key)
+ // 若找到键值对,则用删除标记覆盖它
+ if (buckets[index] != null && buckets[index] != TOMBSTONE) {
+ buckets[index] = TOMBSTONE
+ size--
+ }
+ }
+
+ /* 扩容哈希表 */
+ fun extend() {
+ // 暂存原哈希表
+ val bucketsTmp = buckets
+ // 初始化扩容后的新哈希表
+ capacity *= extendRatio
+ buckets = arrayOfNulls(capacity)
+ size = 0
+ // 将键值对从原哈希表搬运至新哈希表
+ for (pair in bucketsTmp) {
+ if (pair != null && pair != TOMBSTONE) {
+ put(pair.key, pair.value)
+ }
+ }
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (pair in buckets) {
+ if (pair == null) {
+ println("null")
+ } else if (pair == TOMBSTONE) {
+ println("TOMESTOME")
+ } else {
+ println("${pair.key} -> ${pair.value}")
+ }
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="hash_map_open_addressing.zig"
diff --git a/en/docs/chapter_hashing/hash_map.md b/en/docs/chapter_hashing/hash_map.md
index e05ff9b2a..6cbe29657 100755
--- a/en/docs/chapter_hashing/hash_map.md
+++ b/en/docs/chapter_hashing/hash_map.md
@@ -277,6 +277,12 @@ Common operations of a hash table include initialization, querying, adding key-v
// C does not provide a built-in hash table
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map.kt"
+
+ ```
+
=== "Zig"
```zig title="hash_map.zig"
@@ -473,6 +479,12 @@ There are three common ways to traverse a hash table: traversing key-value pairs
// C does not provide a built-in hash table
```
+=== "Kotlin"
+
+ ```kotlin title="hash_map.kt"
+
+ ```
+
=== "Zig"
```zig title="hash_map.zig"
@@ -1525,6 +1537,166 @@ The following code implements a simple hash table. Here, we encapsulate `key` an
}
```
+=== "Kotlin"
+
+ ```kotlin title="array_hash_map.kt"
+ /* 键值对 */
+ class Pair(
+ var key: Int,
+ var value: String
+ )
+
+ /* 基于数组实现的哈希表 */
+ class ArrayHashMap {
+ private val buckets = arrayOfNulls(100)
+
+ init {
+ // 初始化数组,包含 100 个桶
+ for (i in 0..<100) {
+ buckets[i] = null
+ }
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ val index = key % 100
+ return index
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ val index = hashFunc(key)
+ val pair = buckets[index] ?: return null
+ return pair.value
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ val pair = Pair(key, value)
+ val index = hashFunc(key)
+ buckets[index] = pair
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ // 置为 null ,代表删除
+ buckets[index] = null
+ }
+
+ /* 获取所有键值对 */
+ fun pairSet(): MutableList {
+ val pairSet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) pairSet.add(pair)
+ }
+ return pairSet
+ }
+
+ /* 获取所有键 */
+ fun keySet(): MutableList {
+ val keySet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) keySet.add(pair.key)
+ }
+ return keySet
+ }
+
+ /* 获取所有值 */
+ fun valueSet(): MutableList {
+ val valueSet = ArrayList()
+ for (pair in buckets) {
+ pair?.let { valueSet.add(it.value) }
+ }
+ return valueSet
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (kv in pairSet()) {
+ val key = kv.key
+ val value = kv.value
+ println("${key}->${value}")
+ }
+ }
+ }
+
+ /* 基于数组实现的哈希表 */
+ class ArrayHashMap {
+ private val buckets = arrayOfNulls(100)
+
+ init {
+ // 初始化数组,包含 100 个桶
+ for (i in 0..<100) {
+ buckets[i] = null
+ }
+ }
+
+ /* 哈希函数 */
+ fun hashFunc(key: Int): Int {
+ val index = key % 100
+ return index
+ }
+
+ /* 查询操作 */
+ fun get(key: Int): String? {
+ val index = hashFunc(key)
+ val pair = buckets[index] ?: return null
+ return pair.value
+ }
+
+ /* 添加操作 */
+ fun put(key: Int, value: String) {
+ val pair = Pair(key, value)
+ val index = hashFunc(key)
+ buckets[index] = pair
+ }
+
+ /* 删除操作 */
+ fun remove(key: Int) {
+ val index = hashFunc(key)
+ // 置为 null ,代表删除
+ buckets[index] = null
+ }
+
+ /* 获取所有键值对 */
+ fun pairSet(): MutableList {
+ val pairSet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) pairSet.add(pair)
+ }
+ return pairSet
+ }
+
+ /* 获取所有键 */
+ fun keySet(): MutableList {
+ val keySet = ArrayList()
+ for (pair in buckets) {
+ if (pair != null) keySet.add(pair.key)
+ }
+ return keySet
+ }
+
+ /* 获取所有值 */
+ fun valueSet(): MutableList {
+ val valueSet = ArrayList()
+ for (pair in buckets) {
+ pair?.let { valueSet.add(it.value) }
+ }
+ return valueSet
+ }
+
+ /* 打印哈希表 */
+ fun print() {
+ for (kv in pairSet()) {
+ val key = kv.key
+ val value = kv.value
+ println("${key}->${value}")
+ }
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_hash_map.zig"
diff --git a/en/docs/chapter_preface/suggestions.md b/en/docs/chapter_preface/suggestions.md
index 9db805709..1efed419e 100644
--- a/en/docs/chapter_preface/suggestions.md
+++ b/en/docs/chapter_preface/suggestions.md
@@ -160,6 +160,19 @@ comments: true
*/
```
+=== "Kotlin"
+
+ ```kotlin title=""
+ /* Header comments for labeling functions, classes, test samples, etc */
+
+ // Comments for explaining details.
+
+ /**
+ * Multiline
+ * comments
+ */
+ ```
+
=== "Zig"
```zig title=""
diff --git a/en/docs/chapter_stack_and_queue/deque.md b/en/docs/chapter_stack_and_queue/deque.md
index 2cffb54c3..2badf8159 100644
--- a/en/docs/chapter_stack_and_queue/deque.md
+++ b/en/docs/chapter_stack_and_queue/deque.md
@@ -334,6 +334,12 @@ Similarly, we can directly use the double-ended queue classes implemented in pro
// C does not provide a built-in deque
```
+=== "Kotlin"
+
+ ```kotlin title="deque.kt"
+
+ ```
+
=== "Zig"
```zig title="deque.zig"
@@ -1835,6 +1841,133 @@ The implementation code is as follows:
}
```
+=== "Kotlin"
+
+ ```kotlin title="linkedlist_deque.kt"
+ /* 双向链表节点 */
+ class ListNode(var value: Int) {
+ // 节点值
+ var next: ListNode? = null // 后继节点引用
+ var prev: ListNode? = null // 前驱节点引用
+ }
+
+ /* 基于双向链表实现的双向队列 */
+ class LinkedListDeque {
+ private var front: ListNode? = null // 头节点 front ,尾节点 rear
+ private var rear: ListNode? = null
+ private var queSize = 0 // 双向队列的长度
+
+ /* 获取双向队列的长度 */
+ fun size(): Int {
+ return queSize
+ }
+
+ /* 判断双向队列是否为空 */
+ fun isEmpty(): Boolean {
+ return size() == 0
+ }
+
+ /* 入队操作 */
+ fun push(num: Int, isFront: Boolean) {
+ val node = ListNode(num)
+ // 若链表为空,则令 front 和 rear 都指向 node
+ if (isEmpty()) {
+ rear = node
+ front = rear
+ // 队首入队操作
+ } else if (isFront) {
+ // 将 node 添加至链表头部
+ front?.prev = node
+ node.next = front
+ front = node // 更新头节点
+ // 队尾入队操作
+ } else {
+ // 将 node 添加至链表尾部
+ rear?.next = node
+ node.prev = rear
+ rear = node // 更新尾节点
+ }
+ queSize++ // 更新队列长度
+ }
+
+ /* 队首入队 */
+ fun pushFirst(num: Int) {
+ push(num, true)
+ }
+
+ /* 队尾入队 */
+ fun pushLast(num: Int) {
+ push(num, false)
+ }
+
+ /* 出队操作 */
+ fun pop(isFront: Boolean): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+
+ val value: Int
+ // 队首出队操作
+ if (isFront) {
+ value = front!!.value // 暂存头节点值
+ // 删除头节点
+ val fNext = front!!.next
+ if (fNext != null) {
+ fNext.prev = null
+ front!!.next = null
+ }
+ front = fNext // 更新头节点
+ // 队尾出队操作
+ } else {
+ value = rear!!.value // 暂存尾节点值
+ // 删除尾节点
+ val rPrev = rear!!.prev
+ if (rPrev != null) {
+ rPrev.next = null
+ rear!!.prev = null
+ }
+ rear = rPrev // 更新尾节点
+ }
+ queSize-- // 更新队列长度
+ return value
+ }
+
+ /* 队首出队 */
+ fun popFirst(): Int {
+ return pop(true)
+ }
+
+ /* 队尾出队 */
+ fun popLast(): Int {
+ return pop(false)
+ }
+
+ /* 访问队首元素 */
+ fun peekFirst(): Int {
+ if (isEmpty()) {
+ throw IndexOutOfBoundsException()
+
+ }
+ return front!!.value
+ }
+
+ /* 访问队尾元素 */
+ fun peekLast(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return rear!!.value
+ }
+
+ /* 返回数组用于打印 */
+ fun toArray(): IntArray {
+ var node = front
+ val res = IntArray(size())
+ for (i in res.indices) {
+ res[i] = node!!.value
+ node = node.next
+ }
+ return res
+ }
+ }
+ ```
+
=== "Zig"
```zig title="linkedlist_deque.zig"
@@ -2018,9 +2151,1310 @@ As shown in the Figure 5-9 , similar to implementing a queue with an array, we c
The implementation only needs to add methods for "front enqueue" and "rear dequeue":
-```src
-[file]{array_deque}-[func]{}
-```
+=== "Python"
+
+ ```python title="array_deque.py"
+ class ArrayDeque:
+ """基于环形数组实现的双向队列"""
+
+ def __init__(self, capacity: int):
+ """构造方法"""
+ self._nums: list[int] = [0] * capacity
+ self._front: int = 0
+ self._size: int = 0
+
+ def capacity(self) -> int:
+ """获取双向队列的容量"""
+ return len(self._nums)
+
+ def size(self) -> int:
+ """获取双向队列的长度"""
+ return self._size
+
+ def is_empty(self) -> bool:
+ """判断双向队列是否为空"""
+ return self._size == 0
+
+ def index(self, i: int) -> int:
+ """计算环形数组索引"""
+ # 通过取余操作实现数组首尾相连
+ # 当 i 越过数组尾部后,回到头部
+ # 当 i 越过数组头部后,回到尾部
+ return (i + self.capacity()) % self.capacity()
+
+ def push_first(self, num: int):
+ """队首入队"""
+ if self._size == self.capacity():
+ print("双向队列已满")
+ return
+ # 队首指针向左移动一位
+ # 通过取余操作实现 front 越过数组头部后回到尾部
+ self._front = self.index(self._front - 1)
+ # 将 num 添加至队首
+ self._nums[self._front] = num
+ self._size += 1
+
+ def push_last(self, num: int):
+ """队尾入队"""
+ if self._size == self.capacity():
+ print("双向队列已满")
+ return
+ # 计算队尾指针,指向队尾索引 + 1
+ rear = self.index(self._front + self._size)
+ # 将 num 添加至队尾
+ self._nums[rear] = num
+ self._size += 1
+
+ def pop_first(self) -> int:
+ """队首出队"""
+ num = self.peek_first()
+ # 队首指针向后移动一位
+ self._front = self.index(self._front + 1)
+ self._size -= 1
+ return num
+
+ def pop_last(self) -> int:
+ """队尾出队"""
+ num = self.peek_last()
+ self._size -= 1
+ return num
+
+ def peek_first(self) -> int:
+ """访问队首元素"""
+ if self.is_empty():
+ raise IndexError("双向队列为空")
+ return self._nums[self._front]
+
+ def peek_last(self) -> int:
+ """访问队尾元素"""
+ if self.is_empty():
+ raise IndexError("双向队列为空")
+ # 计算尾元素索引
+ last = self.index(self._front + self._size - 1)
+ return self._nums[last]
+
+ def to_array(self) -> list[int]:
+ """返回数组用于打印"""
+ # 仅转换有效长度范围内的列表元素
+ res = []
+ for i in range(self._size):
+ res.append(self._nums[self.index(self._front + i)])
+ return res
+ ```
+
+=== "C++"
+
+ ```cpp title="array_deque.cpp"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ private:
+ vector nums; // 用于存储双向队列元素的数组
+ int front; // 队首指针,指向队首元素
+ int queSize; // 双向队列长度
+
+ public:
+ /* 构造方法 */
+ ArrayDeque(int capacity) {
+ nums.resize(capacity);
+ front = queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ int capacity() {
+ return nums.size();
+ }
+
+ /* 获取双向队列的长度 */
+ int size() {
+ return queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ bool isEmpty() {
+ return queSize == 0;
+ }
+
+ /* 计算环形数组索引 */
+ int index(int i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + capacity()) % capacity();
+ }
+
+ /* 队首入队 */
+ void pushFirst(int num) {
+ if (queSize == capacity()) {
+ cout << "双向队列已满" << endl;
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ front = index(front - 1);
+ // 将 num 添加至队首
+ nums[front] = num;
+ queSize++;
+ }
+
+ /* 队尾入队 */
+ void pushLast(int num) {
+ if (queSize == capacity()) {
+ cout << "双向队列已满" << endl;
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ int rear = index(front + queSize);
+ // 将 num 添加至队尾
+ nums[rear] = num;
+ queSize++;
+ }
+
+ /* 队首出队 */
+ int popFirst() {
+ int num = peekFirst();
+ // 队首指针向后移动一位
+ front = index(front + 1);
+ queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ int popLast() {
+ int num = peekLast();
+ queSize--;
+ return num;
+ }
+
+ /* 访问队首元素 */
+ int peekFirst() {
+ if (isEmpty())
+ throw out_of_range("双向队列为空");
+ return nums[front];
+ }
+
+ /* 访问队尾元素 */
+ int peekLast() {
+ if (isEmpty())
+ throw out_of_range("双向队列为空");
+ // 计算尾元素索引
+ int last = index(front + queSize - 1);
+ return nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ vector toVector() {
+ // 仅转换有效长度范围内的列表元素
+ vector res(queSize);
+ for (int i = 0, j = front; i < queSize; i++, j++) {
+ res[i] = nums[index(j)];
+ }
+ return res;
+ }
+ };
+ ```
+
+=== "Java"
+
+ ```java title="array_deque.java"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ private int[] nums; // 用于存储双向队列元素的数组
+ private int front; // 队首指针,指向队首元素
+ private int queSize; // 双向队列长度
+
+ /* 构造方法 */
+ public ArrayDeque(int capacity) {
+ this.nums = new int[capacity];
+ front = queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ public int capacity() {
+ return nums.length;
+ }
+
+ /* 获取双向队列的长度 */
+ public int size() {
+ return queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ public boolean isEmpty() {
+ return queSize == 0;
+ }
+
+ /* 计算环形数组索引 */
+ private int index(int i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + capacity()) % capacity();
+ }
+
+ /* 队首入队 */
+ public void pushFirst(int num) {
+ if (queSize == capacity()) {
+ System.out.println("双向队列已满");
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ front = index(front - 1);
+ // 将 num 添加至队首
+ nums[front] = num;
+ queSize++;
+ }
+
+ /* 队尾入队 */
+ public void pushLast(int num) {
+ if (queSize == capacity()) {
+ System.out.println("双向队列已满");
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ int rear = index(front + queSize);
+ // 将 num 添加至队尾
+ nums[rear] = num;
+ queSize++;
+ }
+
+ /* 队首出队 */
+ public int popFirst() {
+ int num = peekFirst();
+ // 队首指针向后移动一位
+ front = index(front + 1);
+ queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ public int popLast() {
+ int num = peekLast();
+ queSize--;
+ return num;
+ }
+
+ /* 访问队首元素 */
+ public int peekFirst() {
+ if (isEmpty())
+ throw new IndexOutOfBoundsException();
+ return nums[front];
+ }
+
+ /* 访问队尾元素 */
+ public int peekLast() {
+ if (isEmpty())
+ throw new IndexOutOfBoundsException();
+ // 计算尾元素索引
+ int last = index(front + queSize - 1);
+ return nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ public int[] toArray() {
+ // 仅转换有效长度范围内的列表元素
+ int[] res = new int[queSize];
+ for (int i = 0, j = front; i < queSize; i++, j++) {
+ res[i] = nums[index(j)];
+ }
+ return res;
+ }
+ }
+ ```
+
+=== "C#"
+
+ ```csharp title="array_deque.cs"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ int[] nums; // 用于存储双向队列元素的数组
+ int front; // 队首指针,指向队首元素
+ int queSize; // 双向队列长度
+
+ /* 构造方法 */
+ public ArrayDeque(int capacity) {
+ nums = new int[capacity];
+ front = queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ int Capacity() {
+ return nums.Length;
+ }
+
+ /* 获取双向队列的长度 */
+ public int Size() {
+ return queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ public bool IsEmpty() {
+ return queSize == 0;
+ }
+
+ /* 计算环形数组索引 */
+ int Index(int i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + Capacity()) % Capacity();
+ }
+
+ /* 队首入队 */
+ public void PushFirst(int num) {
+ if (queSize == Capacity()) {
+ Console.WriteLine("双向队列已满");
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ front = Index(front - 1);
+ // 将 num 添加至队首
+ nums[front] = num;
+ queSize++;
+ }
+
+ /* 队尾入队 */
+ public void PushLast(int num) {
+ if (queSize == Capacity()) {
+ Console.WriteLine("双向队列已满");
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ int rear = Index(front + queSize);
+ // 将 num 添加至队尾
+ nums[rear] = num;
+ queSize++;
+ }
+
+ /* 队首出队 */
+ public int PopFirst() {
+ int num = PeekFirst();
+ // 队首指针向后移动一位
+ front = Index(front + 1);
+ queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ public int PopLast() {
+ int num = PeekLast();
+ queSize--;
+ return num;
+ }
+
+ /* 访问队首元素 */
+ public int PeekFirst() {
+ if (IsEmpty()) {
+ throw new InvalidOperationException();
+ }
+ return nums[front];
+ }
+
+ /* 访问队尾元素 */
+ public int PeekLast() {
+ if (IsEmpty()) {
+ throw new InvalidOperationException();
+ }
+ // 计算尾元素索引
+ int last = Index(front + queSize - 1);
+ return nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ public int[] ToArray() {
+ // 仅转换有效长度范围内的列表元素
+ int[] res = new int[queSize];
+ for (int i = 0, j = front; i < queSize; i++, j++) {
+ res[i] = nums[Index(j)];
+ }
+ return res;
+ }
+ }
+ ```
+
+=== "Go"
+
+ ```go title="array_deque.go"
+ /* 基于环形数组实现的双向队列 */
+ type arrayDeque struct {
+ nums []int // 用于存储双向队列元素的数组
+ front int // 队首指针,指向队首元素
+ queSize int // 双向队列长度
+ queCapacity int // 队列容量(即最大容纳元素数量)
+ }
+
+ /* 初始化队列 */
+ func newArrayDeque(queCapacity int) *arrayDeque {
+ return &arrayDeque{
+ nums: make([]int, queCapacity),
+ queCapacity: queCapacity,
+ front: 0,
+ queSize: 0,
+ }
+ }
+
+ /* 获取双向队列的长度 */
+ func (q *arrayDeque) size() int {
+ return q.queSize
+ }
+
+ /* 判断双向队列是否为空 */
+ func (q *arrayDeque) isEmpty() bool {
+ return q.queSize == 0
+ }
+
+ /* 计算环形数组索引 */
+ func (q *arrayDeque) index(i int) int {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + q.queCapacity) % q.queCapacity
+ }
+
+ /* 队首入队 */
+ func (q *arrayDeque) pushFirst(num int) {
+ if q.queSize == q.queCapacity {
+ fmt.Println("双向队列已满")
+ return
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ q.front = q.index(q.front - 1)
+ // 将 num 添加至队首
+ q.nums[q.front] = num
+ q.queSize++
+ }
+
+ /* 队尾入队 */
+ func (q *arrayDeque) pushLast(num int) {
+ if q.queSize == q.queCapacity {
+ fmt.Println("双向队列已满")
+ return
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ rear := q.index(q.front + q.queSize)
+ // 将 num 添加至队首
+ q.nums[rear] = num
+ q.queSize++
+ }
+
+ /* 队首出队 */
+ func (q *arrayDeque) popFirst() any {
+ num := q.peekFirst()
+ // 队首指针向后移动一位
+ q.front = q.index(q.front + 1)
+ q.queSize--
+ return num
+ }
+
+ /* 队尾出队 */
+ func (q *arrayDeque) popLast() any {
+ num := q.peekLast()
+ q.queSize--
+ return num
+ }
+
+ /* 访问队首元素 */
+ func (q *arrayDeque) peekFirst() any {
+ if q.isEmpty() {
+ return nil
+ }
+ return q.nums[q.front]
+ }
+
+ /* 访问队尾元素 */
+ func (q *arrayDeque) peekLast() any {
+ if q.isEmpty() {
+ return nil
+ }
+ // 计算尾元素索引
+ last := q.index(q.front + q.queSize - 1)
+ return q.nums[last]
+ }
+
+ /* 获取 Slice 用于打印 */
+ func (q *arrayDeque) toSlice() []int {
+ // 仅转换有效长度范围内的列表元素
+ res := make([]int, q.queSize)
+ for i, j := 0, q.front; i < q.queSize; i++ {
+ res[i] = q.nums[q.index(j)]
+ j++
+ }
+ return res
+ }
+ ```
+
+=== "Swift"
+
+ ```swift title="array_deque.swift"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ private var nums: [Int] // 用于存储双向队列元素的数组
+ private var front: Int // 队首指针,指向队首元素
+ private var _size: Int // 双向队列长度
+
+ /* 构造方法 */
+ init(capacity: Int) {
+ nums = Array(repeating: 0, count: capacity)
+ front = 0
+ _size = 0
+ }
+
+ /* 获取双向队列的容量 */
+ func capacity() -> Int {
+ nums.count
+ }
+
+ /* 获取双向队列的长度 */
+ func size() -> Int {
+ _size
+ }
+
+ /* 判断双向队列是否为空 */
+ func isEmpty() -> Bool {
+ size() == 0
+ }
+
+ /* 计算环形数组索引 */
+ private func index(i: Int) -> Int {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ (i + capacity()) % capacity()
+ }
+
+ /* 队首入队 */
+ func pushFirst(num: Int) {
+ if size() == capacity() {
+ print("双向队列已满")
+ return
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ front = index(i: front - 1)
+ // 将 num 添加至队首
+ nums[front] = num
+ _size += 1
+ }
+
+ /* 队尾入队 */
+ func pushLast(num: Int) {
+ if size() == capacity() {
+ print("双向队列已满")
+ return
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ let rear = index(i: front + size())
+ // 将 num 添加至队尾
+ nums[rear] = num
+ _size += 1
+ }
+
+ /* 队首出队 */
+ func popFirst() -> Int {
+ let num = peekFirst()
+ // 队首指针向后移动一位
+ front = index(i: front + 1)
+ _size -= 1
+ return num
+ }
+
+ /* 队尾出队 */
+ func popLast() -> Int {
+ let num = peekLast()
+ _size -= 1
+ return num
+ }
+
+ /* 访问队首元素 */
+ func peekFirst() -> Int {
+ if isEmpty() {
+ fatalError("双向队列为空")
+ }
+ return nums[front]
+ }
+
+ /* 访问队尾元素 */
+ func peekLast() -> Int {
+ if isEmpty() {
+ fatalError("双向队列为空")
+ }
+ // 计算尾元素索引
+ let last = index(i: front + size() - 1)
+ return nums[last]
+ }
+
+ /* 返回数组用于打印 */
+ func toArray() -> [Int] {
+ // 仅转换有效长度范围内的列表元素
+ (front ..< front + size()).map { nums[index(i: $0)] }
+ }
+ }
+ ```
+
+=== "JS"
+
+ ```javascript title="array_deque.js"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ #nums; // 用于存储双向队列元素的数组
+ #front; // 队首指针,指向队首元素
+ #queSize; // 双向队列长度
+
+ /* 构造方法 */
+ constructor(capacity) {
+ this.#nums = new Array(capacity);
+ this.#front = 0;
+ this.#queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ capacity() {
+ return this.#nums.length;
+ }
+
+ /* 获取双向队列的长度 */
+ size() {
+ return this.#queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ isEmpty() {
+ return this.#queSize === 0;
+ }
+
+ /* 计算环形数组索引 */
+ index(i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + this.capacity()) % this.capacity();
+ }
+
+ /* 队首入队 */
+ pushFirst(num) {
+ if (this.#queSize === this.capacity()) {
+ console.log('双向队列已满');
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ this.#front = this.index(this.#front - 1);
+ // 将 num 添加至队首
+ this.#nums[this.#front] = num;
+ this.#queSize++;
+ }
+
+ /* 队尾入队 */
+ pushLast(num) {
+ if (this.#queSize === this.capacity()) {
+ console.log('双向队列已满');
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ const rear = this.index(this.#front + this.#queSize);
+ // 将 num 添加至队尾
+ this.#nums[rear] = num;
+ this.#queSize++;
+ }
+
+ /* 队首出队 */
+ popFirst() {
+ const num = this.peekFirst();
+ // 队首指针向后移动一位
+ this.#front = this.index(this.#front + 1);
+ this.#queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ popLast() {
+ const num = this.peekLast();
+ this.#queSize--;
+ return num;
+ }
+
+ /* 访问队首元素 */
+ peekFirst() {
+ if (this.isEmpty()) throw new Error('The Deque Is Empty.');
+ return this.#nums[this.#front];
+ }
+
+ /* 访问队尾元素 */
+ peekLast() {
+ if (this.isEmpty()) throw new Error('The Deque Is Empty.');
+ // 计算尾元素索引
+ const last = this.index(this.#front + this.#queSize - 1);
+ return this.#nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ toArray() {
+ // 仅转换有效长度范围内的列表元素
+ const res = [];
+ for (let i = 0, j = this.#front; i < this.#queSize; i++, j++) {
+ res[i] = this.#nums[this.index(j)];
+ }
+ return res;
+ }
+ }
+ ```
+
+=== "TS"
+
+ ```typescript title="array_deque.ts"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ private nums: number[]; // 用于存储双向队列元素的数组
+ private front: number; // 队首指针,指向队首元素
+ private queSize: number; // 双向队列长度
+
+ /* 构造方法 */
+ constructor(capacity: number) {
+ this.nums = new Array(capacity);
+ this.front = 0;
+ this.queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ capacity(): number {
+ return this.nums.length;
+ }
+
+ /* 获取双向队列的长度 */
+ size(): number {
+ return this.queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ isEmpty(): boolean {
+ return this.queSize === 0;
+ }
+
+ /* 计算环形数组索引 */
+ index(i: number): number {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + this.capacity()) % this.capacity();
+ }
+
+ /* 队首入队 */
+ pushFirst(num: number): void {
+ if (this.queSize === this.capacity()) {
+ console.log('双向队列已满');
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ this.front = this.index(this.front - 1);
+ // 将 num 添加至队首
+ this.nums[this.front] = num;
+ this.queSize++;
+ }
+
+ /* 队尾入队 */
+ pushLast(num: number): void {
+ if (this.queSize === this.capacity()) {
+ console.log('双向队列已满');
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ const rear: number = this.index(this.front + this.queSize);
+ // 将 num 添加至队尾
+ this.nums[rear] = num;
+ this.queSize++;
+ }
+
+ /* 队首出队 */
+ popFirst(): number {
+ const num: number = this.peekFirst();
+ // 队首指针向后移动一位
+ this.front = this.index(this.front + 1);
+ this.queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ popLast(): number {
+ const num: number = this.peekLast();
+ this.queSize--;
+ return num;
+ }
+
+ /* 访问队首元素 */
+ peekFirst(): number {
+ if (this.isEmpty()) throw new Error('The Deque Is Empty.');
+ return this.nums[this.front];
+ }
+
+ /* 访问队尾元素 */
+ peekLast(): number {
+ if (this.isEmpty()) throw new Error('The Deque Is Empty.');
+ // 计算尾元素索引
+ const last = this.index(this.front + this.queSize - 1);
+ return this.nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ toArray(): number[] {
+ // 仅转换有效长度范围内的列表元素
+ const res: number[] = [];
+ for (let i = 0, j = this.front; i < this.queSize; i++, j++) {
+ res[i] = this.nums[this.index(j)];
+ }
+ return res;
+ }
+ }
+ ```
+
+=== "Dart"
+
+ ```dart title="array_deque.dart"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque {
+ late List _nums; // 用于存储双向队列元素的数组
+ late int _front; // 队首指针,指向队首元素
+ late int _queSize; // 双向队列长度
+
+ /* 构造方法 */
+ ArrayDeque(int capacity) {
+ this._nums = List.filled(capacity, 0);
+ this._front = this._queSize = 0;
+ }
+
+ /* 获取双向队列的容量 */
+ int capacity() {
+ return _nums.length;
+ }
+
+ /* 获取双向队列的长度 */
+ int size() {
+ return _queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ bool isEmpty() {
+ return _queSize == 0;
+ }
+
+ /* 计算环形数组索引 */
+ int index(int i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + capacity()) % capacity();
+ }
+
+ /* 队首入队 */
+ void pushFirst(int _num) {
+ if (_queSize == capacity()) {
+ throw Exception("双向队列已满");
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 _front 越过数组头部后回到尾部
+ _front = index(_front - 1);
+ // 将 _num 添加至队首
+ _nums[_front] = _num;
+ _queSize++;
+ }
+
+ /* 队尾入队 */
+ void pushLast(int _num) {
+ if (_queSize == capacity()) {
+ throw Exception("双向队列已满");
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ int rear = index(_front + _queSize);
+ // 将 _num 添加至队尾
+ _nums[rear] = _num;
+ _queSize++;
+ }
+
+ /* 队首出队 */
+ int popFirst() {
+ int _num = peekFirst();
+ // 队首指针向右移动一位
+ _front = index(_front + 1);
+ _queSize--;
+ return _num;
+ }
+
+ /* 队尾出队 */
+ int popLast() {
+ int _num = peekLast();
+ _queSize--;
+ return _num;
+ }
+
+ /* 访问队首元素 */
+ int peekFirst() {
+ if (isEmpty()) {
+ throw Exception("双向队列为空");
+ }
+ return _nums[_front];
+ }
+
+ /* 访问队尾元素 */
+ int peekLast() {
+ if (isEmpty()) {
+ throw Exception("双向队列为空");
+ }
+ // 计算尾元素索引
+ int last = index(_front + _queSize - 1);
+ return _nums[last];
+ }
+
+ /* 返回数组用于打印 */
+ List toArray() {
+ // 仅转换有效长度范围内的列表元素
+ List res = List.filled(_queSize, 0);
+ for (int i = 0, j = _front; i < _queSize; i++, j++) {
+ res[i] = _nums[index(j)];
+ }
+ return res;
+ }
+ }
+ ```
+
+=== "Rust"
+
+ ```rust title="array_deque.rs"
+ /* 基于环形数组实现的双向队列 */
+ struct ArrayDeque {
+ nums: Vec, // 用于存储双向队列元素的数组
+ front: usize, // 队首指针,指向队首元素
+ que_size: usize, // 双向队列长度
+ }
+
+ impl ArrayDeque {
+ /* 构造方法 */
+ pub fn new(capacity: usize) -> Self {
+ Self {
+ nums: vec![0; capacity],
+ front: 0,
+ que_size: 0,
+ }
+ }
+
+ /* 获取双向队列的容量 */
+ pub fn capacity(&self) -> usize {
+ self.nums.len()
+ }
+
+ /* 获取双向队列的长度 */
+ pub fn size(&self) -> usize {
+ self.que_size
+ }
+
+ /* 判断双向队列是否为空 */
+ pub fn is_empty(&self) -> bool {
+ self.que_size == 0
+ }
+
+ /* 计算环形数组索引 */
+ fn index(&self, i: i32) -> usize {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return ((i + self.capacity() as i32) % self.capacity() as i32) as usize;
+ }
+
+ /* 队首入队 */
+ pub fn push_first(&mut self, num: i32) {
+ if self.que_size == self.capacity() {
+ println!("双向队列已满");
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ self.front = self.index(self.front as i32 - 1);
+ // 将 num 添加至队首
+ self.nums[self.front] = num;
+ self.que_size += 1;
+ }
+
+ /* 队尾入队 */
+ pub fn push_last(&mut self, num: i32) {
+ if self.que_size == self.capacity() {
+ println!("双向队列已满");
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ let rear = self.index(self.front as i32 + self.que_size as i32);
+ // 将 num 添加至队尾
+ self.nums[rear] = num;
+ self.que_size += 1;
+ }
+
+ /* 队首出队 */
+ fn pop_first(&mut self) -> i32 {
+ let num = self.peek_first();
+ // 队首指针向后移动一位
+ self.front = self.index(self.front as i32 + 1);
+ self.que_size -= 1;
+ num
+ }
+
+ /* 队尾出队 */
+ fn pop_last(&mut self) -> i32 {
+ let num = self.peek_last();
+ self.que_size -= 1;
+ num
+ }
+
+ /* 访问队首元素 */
+ fn peek_first(&self) -> i32 {
+ if self.is_empty() {
+ panic!("双向队列为空")
+ };
+ self.nums[self.front]
+ }
+
+ /* 访问队尾元素 */
+ fn peek_last(&self) -> i32 {
+ if self.is_empty() {
+ panic!("双向队列为空")
+ };
+ // 计算尾元素索引
+ let last = self.index(self.front as i32 + self.que_size as i32 - 1);
+ self.nums[last]
+ }
+
+ /* 返回数组用于打印 */
+ fn to_array(&self) -> Vec {
+ // 仅转换有效长度范围内的列表元素
+ let mut res = vec![0; self.que_size];
+ let mut j = self.front;
+ for i in 0..self.que_size {
+ res[i] = self.nums[self.index(j as i32)];
+ j += 1;
+ }
+ res
+ }
+ }
+ ```
+
+=== "C"
+
+ ```c title="array_deque.c"
+ /* 基于环形数组实现的双向队列 */
+ typedef struct {
+ int *nums; // 用于存储队列元素的数组
+ int front; // 队首指针,指向队首元素
+ int queSize; // 尾指针,指向队尾 + 1
+ int queCapacity; // 队列容量
+ } ArrayDeque;
+
+ /* 构造函数 */
+ ArrayDeque *newArrayDeque(int capacity) {
+ ArrayDeque *deque = (ArrayDeque *)malloc(sizeof(ArrayDeque));
+ // 初始化数组
+ deque->queCapacity = capacity;
+ deque->nums = (int *)malloc(sizeof(int) * deque->queCapacity);
+ deque->front = deque->queSize = 0;
+ return deque;
+ }
+
+ /* 析构函数 */
+ void delArrayDeque(ArrayDeque *deque) {
+ free(deque->nums);
+ free(deque);
+ }
+
+ /* 获取双向队列的容量 */
+ int capacity(ArrayDeque *deque) {
+ return deque->queCapacity;
+ }
+
+ /* 获取双向队列的长度 */
+ int size(ArrayDeque *deque) {
+ return deque->queSize;
+ }
+
+ /* 判断双向队列是否为空 */
+ bool empty(ArrayDeque *deque) {
+ return deque->queSize == 0;
+ }
+
+ /* 计算环形数组索引 */
+ int dequeIndex(ArrayDeque *deque, int i) {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部时,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return ((i + capacity(deque)) % capacity(deque));
+ }
+
+ /* 队首入队 */
+ void pushFirst(ArrayDeque *deque, int num) {
+ if (deque->queSize == capacity(deque)) {
+ printf("双向队列已满\r\n");
+ return;
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部回到尾部
+ deque->front = dequeIndex(deque, deque->front - 1);
+ // 将 num 添加到队首
+ deque->nums[deque->front] = num;
+ deque->queSize++;
+ }
+
+ /* 队尾入队 */
+ void pushLast(ArrayDeque *deque, int num) {
+ if (deque->queSize == capacity(deque)) {
+ printf("双向队列已满\r\n");
+ return;
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ int rear = dequeIndex(deque, deque->front + deque->queSize);
+ // 将 num 添加至队尾
+ deque->nums[rear] = num;
+ deque->queSize++;
+ }
+
+ /* 访问队首元素 */
+ int peekFirst(ArrayDeque *deque) {
+ // 访问异常:双向队列为空
+ assert(empty(deque) == 0);
+ return deque->nums[deque->front];
+ }
+
+ /* 访问队尾元素 */
+ int peekLast(ArrayDeque *deque) {
+ // 访问异常:双向队列为空
+ assert(empty(deque) == 0);
+ int last = dequeIndex(deque, deque->front + deque->queSize - 1);
+ return deque->nums[last];
+ }
+
+ /* 队首出队 */
+ int popFirst(ArrayDeque *deque) {
+ int num = peekFirst(deque);
+ // 队首指针向后移动一位
+ deque->front = dequeIndex(deque, deque->front + 1);
+ deque->queSize--;
+ return num;
+ }
+
+ /* 队尾出队 */
+ int popLast(ArrayDeque *deque) {
+ int num = peekLast(deque);
+ deque->queSize--;
+ return num;
+ }
+ ```
+
+=== "Kotlin"
+
+ ```kotlin title="array_deque.kt"
+ /* 基于环形数组实现的双向队列 */
+ class ArrayDeque(capacity: Int) {
+ private var nums = IntArray(capacity) // 用于存储双向队列元素的数组
+ private var front = 0 // 队首指针,指向队首元素
+ private var queSize = 0 // 双向队列长度
+
+ /* 获取双向队列的容量 */
+ fun capacity(): Int {
+ return nums.size
+ }
+
+ /* 获取双向队列的长度 */
+ fun size(): Int {
+ return queSize
+ }
+
+ /* 判断双向队列是否为空 */
+ fun isEmpty(): Boolean {
+ return queSize == 0
+ }
+
+ /* 计算环形数组索引 */
+ private fun index(i: Int): Int {
+ // 通过取余操作实现数组首尾相连
+ // 当 i 越过数组尾部后,回到头部
+ // 当 i 越过数组头部后,回到尾部
+ return (i + capacity()) % capacity()
+ }
+
+ /* 队首入队 */
+ fun pushFirst(num: Int) {
+ if (queSize == capacity()) {
+ println("双向队列已满")
+ return
+ }
+ // 队首指针向左移动一位
+ // 通过取余操作实现 front 越过数组头部后回到尾部
+ front = index(front - 1)
+ // 将 num 添加至队首
+ nums[front] = num
+ queSize++
+ }
+
+ /* 队尾入队 */
+ fun pushLast(num: Int) {
+ if (queSize == capacity()) {
+ println("双向队列已满")
+ return
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ val rear = index(front + queSize)
+ // 将 num 添加至队尾
+ nums[rear] = num
+ queSize++
+ }
+
+ /* 队首出队 */
+ fun popFirst(): Int {
+ val num = peekFirst()
+ // 队首指针向后移动一位
+ front = index(front + 1)
+ queSize--
+ return num
+ }
+
+ /* 访问队尾元素 */
+ fun popLast(): Int {
+ val num = peekLast()
+ queSize--
+ return num
+ }
+
+ /* 访问队首元素 */
+ fun peekFirst(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return nums[front]
+ }
+
+ /* 访问队尾元素 */
+ fun peekLast(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ // 计算尾元素索引
+ val last = index(front + queSize - 1)
+ return nums[last]
+ }
+
+ /* 返回数组用于打印 */
+ fun toArray(): IntArray {
+ // 仅转换有效长度范围内的列表元素
+ val res = IntArray(queSize)
+ var i = 0
+ var j = front
+ while (i < queSize) {
+ res[i] = nums[index(j)]
+ i++
+ j++
+ }
+ return res
+ }
+ }
+ ```
+
+=== "Zig"
+
+ ```zig title="array_deque.zig"
+ [class]{ArrayDeque}-[func]{}
+ ```
## 5.3.3 Applications of Double-Ended Queue
diff --git a/en/docs/chapter_stack_and_queue/queue.md b/en/docs/chapter_stack_and_queue/queue.md
index f4fdf94c6..0a62b4dd5 100755
--- a/en/docs/chapter_stack_and_queue/queue.md
+++ b/en/docs/chapter_stack_and_queue/queue.md
@@ -312,6 +312,12 @@ We can directly use the ready-made queue classes in programming languages:
// C does not provide a built-in queue
```
+=== "Kotlin"
+
+ ```kotlin title="queue.kt"
+
+ ```
+
=== "Zig"
```zig title="queue.zig"
@@ -1125,6 +1131,71 @@ Below is the code for implementing a queue using a linked list:
}
```
+=== "Kotlin"
+
+ ```kotlin title="linkedlist_queue.kt"
+ /* 基于链表实现的队列 */
+ class LinkedListQueue(
+ // 头节点 front ,尾节点 rear
+ private var front: ListNode? = null,
+ private var rear: ListNode? = null,
+ private var queSize: Int = 0
+ ) {
+
+ /* 获取队列的长度 */
+ fun size(): Int {
+ return queSize
+ }
+
+ /* 判断队列是否为空 */
+ fun isEmpty(): Boolean {
+ return size() == 0
+ }
+
+ /* 入队 */
+ fun push(num: Int) {
+ // 在尾节点后添加 num
+ val node = ListNode(num)
+ // 如果队列为空,则令头、尾节点都指向该节点
+ if (front == null) {
+ front = node
+ rear = node
+ // 如果队列不为空,则将该节点添加到尾节点后
+ } else {
+ rear?.next = node
+ rear = node
+ }
+ queSize++
+ }
+
+ /* 出队 */
+ fun pop(): Int {
+ val num = peek()
+ // 删除头节点
+ front = front?.next
+ queSize--
+ return num
+ }
+
+ /* 访问队首元素 */
+ fun peek(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return front!!.value
+ }
+
+ /* 将链表转化为 Array 并返回 */
+ fun toArray(): IntArray {
+ var node = front
+ val res = IntArray(size())
+ for (i in res.indices) {
+ res[i] = node!!.value
+ node = node.next
+ }
+ return res
+ }
+ }
+ ```
+
=== "Zig"
```zig title="linkedlist_queue.zig"
@@ -2036,6 +2107,75 @@ In a circular array, `front` or `rear` needs to loop back to the start of the ar
}
```
+=== "Kotlin"
+
+ ```kotlin title="array_queue.kt"
+ /* 基于环形数组实现的队列 */
+ class ArrayQueue(capacity: Int) {
+ private val nums = IntArray(capacity) // 用于存储队列元素的数组
+ private var front = 0 // 队首指针,指向队首元素
+ private var queSize = 0 // 队列长度
+
+ /* 获取队列的容量 */
+ fun capacity(): Int {
+ return nums.size
+ }
+
+ /* 获取队列的长度 */
+ fun size(): Int {
+ return queSize
+ }
+
+ /* 判断队列是否为空 */
+ fun isEmpty(): Boolean {
+ return queSize == 0
+ }
+
+ /* 入队 */
+ fun push(num: Int) {
+ if (queSize == capacity()) {
+ println("队列已满")
+ return
+ }
+ // 计算队尾指针,指向队尾索引 + 1
+ // 通过取余操作实现 rear 越过数组尾部后回到头部
+ val rear = (front + queSize) % capacity()
+ // 将 num 添加至队尾
+ nums[rear] = num
+ queSize++
+ }
+
+ /* 出队 */
+ fun pop(): Int {
+ val num = peek()
+ // 队首指针向后移动一位,若越过尾部,则返回到数组头部
+ front = (front + 1) % capacity()
+ queSize--
+ return num
+ }
+
+ /* 访问队首元素 */
+ fun peek(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return nums[front]
+ }
+
+ /* 返回数组 */
+ fun toArray(): IntArray {
+ // 仅转换有效长度范围内的列表元素
+ val res = IntArray(queSize)
+ var i = 0
+ var j = front
+ while (i < queSize) {
+ res[i] = nums[j % capacity()]
+ i++
+ j++
+ }
+ return res
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_queue.zig"
diff --git a/en/docs/chapter_stack_and_queue/stack.md b/en/docs/chapter_stack_and_queue/stack.md
index db50d987b..4f028c3ff 100755
--- a/en/docs/chapter_stack_and_queue/stack.md
+++ b/en/docs/chapter_stack_and_queue/stack.md
@@ -306,6 +306,12 @@ Typically, we can directly use the stack class built into the programming langua
// C does not provide a built-in stack
```
+=== "Kotlin"
+
+ ```kotlin title="stack.kt"
+
+ ```
+
=== "Zig"
```zig title="stack.zig"
@@ -1008,6 +1014,60 @@ Below is an example code for implementing a stack based on a linked list:
}
```
+=== "Kotlin"
+
+ ```kotlin title="linkedlist_stack.kt"
+ /* 基于链表实现的栈 */
+ class LinkedListStack(
+ private var stackPeek: ListNode? = null, // 将头节点作为栈顶
+ private var stkSize: Int = 0 // 栈的长度
+ ) {
+
+ /* 获取栈的长度 */
+ fun size(): Int {
+ return stkSize
+ }
+
+ /* 判断栈是否为空 */
+ fun isEmpty(): Boolean {
+ return size() == 0
+ }
+
+ /* 入栈 */
+ fun push(num: Int) {
+ val node = ListNode(num)
+ node.next = stackPeek
+ stackPeek = node
+ stkSize++
+ }
+
+ /* 出栈 */
+ fun pop(): Int? {
+ val num = peek()
+ stackPeek = stackPeek?.next
+ stkSize--;
+ return num
+ }
+
+ /* 访问栈顶元素 */
+ fun peek(): Int? {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return stackPeek?.value
+ }
+
+ /* 将 List 转化为 Array 并返回 */
+ fun toArray(): IntArray {
+ var node = stackPeek
+ val res = IntArray(size())
+ for (i in res.size - 1 downTo 0) {
+ res[i] = node?.value!!
+ node = node.next
+ }
+ return res
+ }
+ }
+ ```
+
=== "Zig"
```zig title="linkedlist_stack.zig"
@@ -1643,6 +1703,48 @@ Since the elements to be pushed onto the stack may continuously increase, we can
}
```
+=== "Kotlin"
+
+ ```kotlin title="array_stack.kt"
+ /* 基于数组实现的栈 */
+ class ArrayStack {
+ // 初始化列表(动态数组)
+ private val stack = ArrayList()
+
+ /* 获取栈的长度 */
+ fun size(): Int {
+ return stack.size
+ }
+
+ /* 判断栈是否为空 */
+ fun isEmpty(): Boolean {
+ return size() == 0
+ }
+
+ /* 入栈 */
+ fun push(num: Int) {
+ stack.add(num)
+ }
+
+ /* 出栈 */
+ fun pop(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return stack.removeAt(size() - 1)
+ }
+
+ /* 访问栈顶元素 */
+ fun peek(): Int {
+ if (isEmpty()) throw IndexOutOfBoundsException()
+ return stack[size() - 1]
+ }
+
+ /* 将 List 转化为 Array 并返回 */
+ fun toArray(): Array {
+ return stack.toArray()
+ }
+ }
+ ```
+
=== "Zig"
```zig title="array_stack.zig"
diff --git a/overrides/stylesheets/extra.css b/overrides/stylesheets/extra.css
index cccaabc20..67f0d38d2 100644
--- a/overrides/stylesheets/extra.css
+++ b/overrides/stylesheets/extra.css
@@ -207,6 +207,11 @@ body {
width: 1.25em;
}
+/* code block tabs */
+.md-typeset .tabbed-labels>label {
+ font-size: 0.59rem;
+}
+
/* header banner */
.md-banner {
background-color: var(--md-code-bg-color);