Many bug fixes and improvements (#1270)

* Add Ruby and Kotlin icons
Add the avatar of @curtishd

* Update README

* Synchronize zh-hant and zh versions.

* Translate the pythontutor blocks to traditional Chinese

* Fix en/mkdocs.yml

* Update the landing page of the en version.

* Fix the Dockerfile

* Refine the en landingpage

* Fix en landing page

* Reset the README.md
This commit is contained in:
Yudong Jin
2024-04-11 20:18:19 +08:00
committed by GitHub
parent 07977184ad
commit b2f0d4603d
192 changed files with 2382 additions and 1196 deletions
@@ -55,7 +55,7 @@ fun traverse(nums: IntArray) {
count += nums[i]
}
// 直接走訪陣列元素
for (j: Int in nums) {
for (j in nums) {
count += j
}
}
@@ -63,7 +63,8 @@ fun traverse(nums: IntArray) {
/* 在陣列中查詢指定元素 */
fun find(nums: IntArray, target: Int): Int {
for (i in nums.indices) {
if (nums[i] == target) return i
if (nums[i] == target)
return i
}
return -1
}
@@ -9,7 +9,7 @@ package chapter_array_and_linkedlist
import utils.ListNode
import utils.printLinkedList
/* 在鏈結串列的節點 n0 之後插入節點p */
/* 在鏈結串列的節點 n0 之後插入節點 P */
fun insert(n0: ListNode?, p: ListNode?) {
val n1 = n0?.next
p?.next = n1
@@ -18,16 +18,20 @@ fun insert(n0: ListNode?, p: ListNode?) {
/* 刪除鏈結串列的節點 n0 之後的首個節點 */
fun remove(n0: ListNode?) {
val p = n0?.next
if (n0?.next == null)
return
val p = n0.next
val n1 = p?.next
n0?.next = n1
n0.next = n1
}
/* 訪問鏈結串列中索引為 index 的節點 */
fun access(head: ListNode?, index: Int): ListNode? {
var h = head
for (i in 0..<index) {
h = h?.next
if (h == null)
return null
h = h.next
}
return h
}
@@ -37,7 +41,8 @@ fun find(head: ListNode?, target: Int): Int {
var index = 0
var h = head
while (h != null) {
if (h.value == target) return index
if (h._val == target)
return index
h = h.next
index++
}
@@ -46,6 +51,7 @@ fun find(head: ListNode?, target: Int): Int {
/* Driver Code */
fun main() {
/* 初始化鏈結串列 */
// 初始化各個節點
val n0 = ListNode(1)
val n1 = ListNode(3)
@@ -60,7 +66,8 @@ fun main() {
n3.next = n4
println("初始化的鏈結串列為")
printLinkedList(n0)
/* 插入節點 */
insert(n0, ListNode(0))
println("插入節點後的鏈結串列為")
printLinkedList(n0)
@@ -72,7 +79,7 @@ fun main() {
/* 訪問節點 */
val node: ListNode = access(n0, 3)!!
println("鏈結串列中索引 3 處的節點的值 = ${node.value}")
println("鏈結串列中索引 3 處的節點的值 = ${node._val}")
/* 查詢節點 */
val index: Int = find(n0, 2)
@@ -8,9 +8,9 @@ package chapter_array_and_linkedlist
/* Driver Code */
fun main() {
/* 初始化串列 */
// 可變集合
val numbers = mutableListOf(1, 3, 2, 5, 4)
val nums = ArrayList<Int>(numbers)
val nums = mutableListOf(1, 3, 2, 5, 4)
println("串列 nums = $nums")
/* 訪問元素 */
@@ -53,11 +53,11 @@ fun main() {
}
/* 拼接兩個串列*/
val nums1 = ArrayList<Int>(listOf(6, 8, 7, 10, 9))
val nums1 = mutableListOf(6, 8, 7, 10, 9)
nums.addAll(nums1)
println("將串列 nums1 拼接到 nums 之後,得到 nums = $nums")
/* 排序串列 */
nums.sort() //排序後,串列元素從小到大排列
nums.sort()
println("排序串列後 nums = $nums")
}
@@ -9,9 +9,9 @@ package chapter_array_and_linkedlist
/* 串列類別 */
class MyList {
private var arr: IntArray = intArrayOf() // 陣列(儲存串列元素)
private var capacity = 10 // 串列容量
private var size = 0 // 串列長度(當前元素數量)
private var extendRatio = 2 // 每次串列擴容的倍數
private var capacity: Int = 10 // 串列容量
private var size: Int = 0 // 串列長度(當前元素數量)
private var extendRatio: Int = 2 // 每次串列擴容的倍數
/* 建構子 */
init {
@@ -32,7 +32,7 @@ class MyList {
fun get(index: Int): Int {
// 索引如果越界,則丟擲異常,下同
if (index < 0 || index >= size)
throw IndexOutOfBoundsException()
throw IndexOutOfBoundsException("索引越界")
return arr[index]
}
@@ -72,7 +72,7 @@ class MyList {
fun remove(index: Int): Int {
if (index < 0 || index >= size)
throw IndexOutOfBoundsException("索引越界")
val num: Int = arr[index]
val num = arr[index]
// 將將索引 index 之後的元素都向前移動一位
for (j in index..<size - 1)
arr[j] = arr[j + 1]
@@ -10,17 +10,17 @@ package chapter_backtracking.n_queens
fun backtrack(
row: Int,
n: Int,
state: List<MutableList<String>>,
res: MutableList<List<List<String>>?>,
state: MutableList<MutableList<String>>,
res: MutableList<MutableList<MutableList<String>>?>,
cols: BooleanArray,
diags1: BooleanArray,
diags2: BooleanArray
) {
// 當放置完所有行時,記錄解
if (row == n) {
val copyState: MutableList<List<String>> = ArrayList()
val copyState = mutableListOf<MutableList<String>>()
for (sRow in state) {
copyState.add(ArrayList(sRow))
copyState.add(sRow.toMutableList())
}
res.add(copyState)
return
@@ -49,11 +49,11 @@ fun backtrack(
}
/* 求解 n 皇后 */
fun nQueens(n: Int): List<List<List<String>>?> {
fun nQueens(n: Int): MutableList<MutableList<MutableList<String>>?> {
// 初始化 n*n 大小的棋盤,其中 'Q' 代表皇后,'#' 代表空位
val state: MutableList<MutableList<String>> = ArrayList()
val state = mutableListOf<MutableList<String>>()
for (i in 0..<n) {
val row: MutableList<String> = ArrayList()
val row = mutableListOf<String>()
for (j in 0..<n) {
row.add("#")
}
@@ -62,7 +62,7 @@ fun nQueens(n: Int): List<List<List<String>>?> {
val cols = BooleanArray(n) // 記錄列是否有皇后
val diags1 = BooleanArray(2 * n - 1) // 記錄主對角線上是否有皇后
val diags2 = BooleanArray(2 * n - 1) // 記錄次對角線上是否有皇后
val res: MutableList<List<List<String>>?> = ArrayList()
val res = mutableListOf<MutableList<MutableList<String>>?>()
backtrack(0, n, state, res, cols, diags1, diags2)
@@ -72,7 +72,7 @@ fun nQueens(n: Int): List<List<List<String>>?> {
/* Driver Code */
fun main() {
val n = 4
val res: List<List<List<String?>?>?> = nQueens(n)
val res = nQueens(n)
println("輸入棋盤長寬為 $n")
println("皇后放置方案共有 ${res.size}")
@@ -11,11 +11,11 @@ fun backtrack(
state: MutableList<Int>,
choices: IntArray,
selected: BooleanArray,
res: MutableList<List<Int>?>
res: MutableList<MutableList<Int>?>
) {
// 當狀態長度等於元素數量時,記錄解
if (state.size == choices.size) {
res.add(ArrayList(state))
res.add(state.toMutableList())
return
}
// 走訪所有選擇
@@ -36,9 +36,9 @@ fun backtrack(
}
/* 全排列 I */
fun permutationsI(nums: IntArray): List<List<Int>?> {
val res: MutableList<List<Int>?> = ArrayList()
backtrack(ArrayList(), nums, BooleanArray(nums.size), res)
fun permutationsI(nums: IntArray): MutableList<MutableList<Int>?> {
val res = mutableListOf<MutableList<Int>?>()
backtrack(mutableListOf(), nums, BooleanArray(nums.size), res)
return res
}
@@ -15,11 +15,11 @@ fun backtrack(
) {
// 當狀態長度等於元素數量時,記錄解
if (state.size == choices.size) {
res.add(ArrayList(state))
res.add(state.toMutableList())
return
}
// 走訪所有選擇
val duplicated: MutableSet<Int> = HashSet()
val duplicated = HashSet<Int>()
for (i in choices.indices) {
val choice = choices[i]
// 剪枝:不允許重複選擇元素 且 不允許重複選擇相等元素
@@ -39,15 +39,14 @@ fun backtrack(
/* 全排列 II */
fun permutationsII(nums: IntArray): MutableList<MutableList<Int>?> {
val res: MutableList<MutableList<Int>?> = ArrayList()
backtrack(ArrayList(), nums, BooleanArray(nums.size), res)
val res = mutableListOf<MutableList<Int>?>()
backtrack(mutableListOf(), nums, BooleanArray(nums.size), res)
return res
}
/* Driver Code */
fun main() {
val nums = intArrayOf(1, 2, 2)
val res = permutationsII(nums)
println("輸入陣列 nums = ${nums.contentToString()}")
@@ -16,7 +16,7 @@ fun preOrder(root: TreeNode?) {
if (root == null) {
return
}
if (root.value == 7) {
if (root._val == 7) {
// 記錄解
res!!.add(root)
}
@@ -31,13 +31,13 @@ fun main() {
printTree(root)
// 前序走訪
res = ArrayList()
res = mutableListOf()
preOrder(root)
println("\n輸出所有值為 7 的節點")
val vals: MutableList<Int> = ArrayList()
for (node in res as ArrayList<TreeNode>) {
vals.add(node.value)
val vals = mutableListOf<Int>()
for (node in res!!) {
vals.add(node._val)
}
println(vals)
}
@@ -10,7 +10,7 @@ import utils.TreeNode
import utils.printTree
var path: MutableList<TreeNode>? = null
var res: MutableList<List<TreeNode>>? = null
var res: MutableList<MutableList<TreeNode>>? = null
/* 前序走訪:例題二 */
fun preOrder(root: TreeNode?) {
@@ -19,9 +19,9 @@ fun preOrder(root: TreeNode?) {
}
// 嘗試
path!!.add(root)
if (root.value == 7) {
if (root._val == 7) {
// 記錄解
res!!.add(ArrayList(path!!))
res!!.add(path!!.toMutableList())
}
preOrder(root.left)
preOrder(root.right)
@@ -36,16 +36,16 @@ fun main() {
printTree(root)
// 前序走訪
path = java.util.ArrayList<TreeNode>()
res = java.util.ArrayList<List<TreeNode>>()
path = mutableListOf()
res = mutableListOf()
preOrder(root)
println("\n輸出所有根節點到節點 7 的路徑")
for (path in res as ArrayList<List<TreeNode>>) {
val values: MutableList<Int> = ArrayList()
for (path in res!!) {
val _vals = mutableListOf<Int>()
for (node in path) {
values.add(node.value)
_vals.add(node._val)
}
println(values)
println(_vals)
}
}
@@ -10,19 +10,19 @@ import utils.TreeNode
import utils.printTree
var path: MutableList<TreeNode>? = null
var res: MutableList<List<TreeNode>>? = null
var res: MutableList<MutableList<TreeNode>>? = null
/* 前序走訪:例題三 */
fun preOrder(root: TreeNode?) {
// 剪枝
if (root == null || root.value == 3) {
if (root == null || root._val == 3) {
return
}
// 嘗試
path!!.add(root)
if (root.value == 7) {
if (root._val == 7) {
// 記錄解
res!!.add(ArrayList(path!!))
res!!.add(path!!.toMutableList())
}
preOrder(root.left)
preOrder(root.right)
@@ -37,16 +37,16 @@ fun main() {
printTree(root)
// 前序走訪
path = ArrayList()
res = ArrayList()
path = mutableListOf()
res = mutableListOf()
preOrder(root)
println("\n輸出所有根節點到節點 7 的路徑,路徑中不包含值為 3 的節點")
for (path in res as ArrayList<List<TreeNode>>) {
val values: MutableList<Int> = ArrayList()
for (path in res!!) {
val _vals = mutableListOf<Int>()
for (node in path) {
values.add(node.value)
_vals.add(node._val)
}
println(values)
println(_vals)
}
}
@@ -8,21 +8,20 @@ package chapter_backtracking.preorder_traversal_iii_template
import utils.TreeNode
import utils.printTree
import java.util.*
/* 判斷當前狀態是否為解 */
fun isSolution(state: List<TreeNode?>): Boolean {
return state.isNotEmpty() && state[state.size - 1]?.value == 7
fun isSolution(state: MutableList<TreeNode?>): Boolean {
return state.isNotEmpty() && state[state.size - 1]?._val == 7
}
/* 記錄解 */
fun recordSolution(state: MutableList<TreeNode?>?, res: MutableList<List<TreeNode?>?>) {
res.add(state?.let { ArrayList(it) })
fun recordSolution(state: MutableList<TreeNode?>?, res: MutableList<MutableList<TreeNode?>?>) {
res.add(state!!.toMutableList())
}
/* 判斷在當前狀態下,該選擇是否合法 */
fun isValid(state: List<TreeNode?>?, choice: TreeNode?): Boolean {
return choice != null && choice.value != 3
fun isValid(state: MutableList<TreeNode?>?, choice: TreeNode?): Boolean {
return choice != null && choice._val != 3
}
/* 更新狀態 */
@@ -38,8 +37,8 @@ fun undoChoice(state: MutableList<TreeNode?>, choice: TreeNode?) {
/* 回溯演算法:例題三 */
fun backtrack(
state: MutableList<TreeNode?>,
choices: List<TreeNode?>,
res: MutableList<List<TreeNode?>?>
choices: MutableList<TreeNode?>,
res: MutableList<MutableList<TreeNode?>?>
) {
// 檢查是否為解
if (isSolution(state)) {
@@ -53,7 +52,7 @@ fun backtrack(
// 嘗試:做出選擇,更新狀態
makeChoice(state, choice)
// 進行下一輪選擇
backtrack(state, listOf(choice!!.left, choice.right), res)
backtrack(state, mutableListOf(choice!!.left, choice.right), res)
// 回退:撤銷選擇,恢復到之前的狀態
undoChoice(state, choice)
}
@@ -67,15 +66,15 @@ fun main() {
printTree(root)
// 回溯演算法
val res: MutableList<List<TreeNode?>?> = ArrayList()
backtrack(ArrayList(), mutableListOf(root), res)
val res = mutableListOf<MutableList<TreeNode?>?>()
backtrack(mutableListOf(), mutableListOf(root), res)
println("\n輸出所有根節點到節點 7 的路徑,要求路徑中不包含值為 3 的節點")
for (path in res) {
val vals = ArrayList<Int>()
val vals = mutableListOf<Int>()
for (node in path!!) {
if (node != null) {
vals.add(node.value)
vals.add(node._val)
}
}
println(vals)
@@ -6,19 +6,17 @@
package chapter_backtracking.subset_sum_i
import java.util.*
/* 回溯演算法:子集和 I */
fun backtrack(
state: MutableList<Int>,
target: Int,
choices: IntArray,
start: Int,
res: MutableList<List<Int>?>
res: MutableList<MutableList<Int>?>
) {
// 子集和等於 target 時,記錄解
if (target == 0) {
res.add(ArrayList(state))
res.add(state.toMutableList())
return
}
// 走訪所有選擇
@@ -39,11 +37,11 @@ fun backtrack(
}
/* 求解子集和 I */
fun subsetSumI(nums: IntArray, target: Int): List<List<Int>?> {
val state: MutableList<Int> = ArrayList() // 狀態(子集)
Arrays.sort(nums) // 對 nums 進行排序
fun subsetSumI(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
val state = mutableListOf<Int>() // 狀態(子集)
nums.sort() // 對 nums 進行排序
val start = 0 // 走訪起始點
val res: MutableList<List<Int>?> = ArrayList() // 結果串列(子集串列)
val res = mutableListOf<MutableList<Int>?>() // 結果串列(子集串列)
backtrack(state, target, nums, start, res)
return res
}
@@ -12,11 +12,11 @@ fun backtrack(
target: Int,
total: Int,
choices: IntArray,
res: MutableList<List<Int>?>
res: MutableList<MutableList<Int>?>
) {
// 子集和等於 target 時,記錄解
if (total == target) {
res.add(ArrayList(state))
res.add(state.toMutableList())
return
}
// 走訪所有選擇
@@ -35,10 +35,10 @@ fun backtrack(
}
/* 求解子集和 I(包含重複子集) */
fun subsetSumINaive(nums: IntArray, target: Int): List<List<Int>?> {
val state: MutableList<Int> = ArrayList() // 狀態(子集)
fun subsetSumINaive(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
val state = mutableListOf<Int>() // 狀態(子集)
val total = 0 // 子集和
val res: MutableList<List<Int>?> = ArrayList() // 結果串列(子集串列)
val res = mutableListOf<MutableList<Int>?>() // 結果串列(子集串列)
backtrack(state, target, total, nums, res)
return res
}
@@ -47,8 +47,7 @@ fun subsetSumINaive(nums: IntArray, target: Int): List<List<Int>?> {
fun main() {
val nums = intArrayOf(3, 4, 5)
val target = 9
val res: List<List<Int>?> = subsetSumINaive(nums, target)
val res = subsetSumINaive(nums, target)
println("輸入陣列 nums = ${nums.contentToString()}, target = $target")
println("所有和等於 $target 的子集 res = $res")
@@ -6,19 +6,17 @@
package chapter_backtracking.subset_sum_ii
import java.util.*
/* 回溯演算法:子集和 II */
fun backtrack(
state: MutableList<Int>,
target: Int,
choices: IntArray,
start: Int,
res: MutableList<List<Int>?>
res: MutableList<MutableList<Int>?>
) {
// 子集和等於 target 時,記錄解
if (target == 0) {
res.add(ArrayList(state))
res.add(state.toMutableList())
return
}
// 走訪所有選擇
@@ -44,11 +42,11 @@ fun backtrack(
}
/* 求解子集和 II */
fun subsetSumII(nums: IntArray, target: Int): List<List<Int>?> {
val state: MutableList<Int> = ArrayList() // 狀態(子集)
Arrays.sort(nums) // 對 nums 進行排序
fun subsetSumII(nums: IntArray, target: Int): MutableList<MutableList<Int>?> {
val state = mutableListOf<Int>() // 狀態(子集)
nums.sort() // 對 nums 進行排序
val start = 0 // 走訪起始點
val res: MutableList<List<Int>?> = ArrayList() // 結果串列(子集串列)
val res = mutableListOf<MutableList<Int>?>() // 結果串列(子集串列)
backtrack(state, target, nums, start, res)
return res
}
@@ -57,7 +55,6 @@ fun subsetSumII(nums: IntArray, target: Int): List<List<Int>?> {
fun main() {
val nums = intArrayOf(4, 4, 5)
val target = 9
val res = subsetSumII(nums, target)
println("輸入陣列 nums = ${nums.contentToString()}, target = $target")
@@ -74,4 +74,4 @@ fun main() {
res = fib(n)
println("\n費波那契數列的第 $n 項為 $res")
}
}
@@ -60,9 +60,9 @@ fun linearRecur(n: Int) {
/* 平方階 */
fun quadratic(n: Int) {
// 矩陣佔用 O(n^2) 空間
val numMatrix: Array<Array<Int>?> = arrayOfNulls(n)
val numMatrix = arrayOfNulls<Array<Int>?>(n)
// 二維串列佔用 O(n^2) 空間
val numList: MutableList<MutableList<Int>> = arrayListOf()
val numList = mutableListOf<MutableList<Int>>()
for (i in 0..<n) {
val tmp = mutableListOf<Int>()
for (j in 0..<n) {
@@ -104,6 +104,6 @@ fun main() {
quadratic(n)
quadraticRecur(n)
// 指數階
val root: TreeNode? = buildTree(n)
val root = buildTree(n)
printTree(root)
}
@@ -9,7 +9,7 @@ package chapter_computational_complexity.time_complexity
/* 常數階 */
fun constant(n: Int): Int {
var count = 0
val size = 10_0000
val size = 100000
for (i in 0..<size)
count++
return count
@@ -48,7 +48,7 @@ fun quadratic(n: Int): Int {
/* 平方階(泡沫排序) */
fun bubbleSort(nums: IntArray): Int {
var count = 0
var count = 0 // 計數器
// 外迴圈:未排序區間為 [0, i]
for (i in nums.size - 1 downTo 1) {
// 內迴圈:將未排序區間 [0, i] 中的最大元素交換至該區間的最右端
@@ -109,7 +109,7 @@ fun linearLogRecur(n: Int): Int {
if (n <= 1)
return 1
var count = linearLogRecur(n / 2) + linearLogRecur(n / 2)
for (i in 0..<n.toInt()) {
for (i in 0..<n) {
count++
}
return count
@@ -133,7 +133,7 @@ fun main() {
val n = 8
println("輸入資料大小 n = $n")
var count: Int = constant(n)
var count = constant(n)
println("常數階的操作數量 = $count")
count = linear(n)
@@ -144,7 +144,8 @@ fun main() {
count = quadratic(n)
println("平方階的操作數量 = $count")
val nums = IntArray(n)
for (i in 0..<n) nums[i] = n - i // [n,n-1,...,2,1]
for (i in 0..<n)
nums[i] = n - i // [n,n-1,...,2,1]
count = bubbleSort(nums)
println("平方階(泡沫排序)的操作數量 = $count")
@@ -13,10 +13,9 @@ fun randomNumbers(n: Int): Array<Int?> {
for (i in 0..<n) {
nums[i] = i + 1
}
// 隨機打亂陣列元素
val mutableList = nums.toMutableList()
// 隨機打亂陣列元素
mutableList.shuffle()
// Integer[] -> int[]
val res = arrayOfNulls<Int>(n)
for (i in 0..<n) {
res[i] = mutableList[i]
@@ -39,8 +38,8 @@ fun findOne(nums: Array<Int?>): Int {
fun main() {
for (i in 0..9) {
val n = 100
val nums: Array<Int?> = randomNumbers(n)
val index: Int = findOne(nums)
val nums = randomNumbers(n)
val index = findOne(nums)
println("\n陣列 [ 1, 2, ..., n ] 被打亂後 = ${nums.contentToString()}")
println("數字 1 的索引為 $index")
}
@@ -10,7 +10,13 @@ import utils.TreeNode
import utils.printTree
/* 構建二元樹:分治 */
fun dfs(preorder: IntArray, inorderMap: Map<Int?, Int?>, i: Int, l: Int, r: Int): TreeNode? {
fun dfs(
preorder: IntArray,
inorderMap: Map<Int?, Int?>,
i: Int,
l: Int,
r: Int
): TreeNode? {
// 子樹區間為空時終止
if (r - l < 0) return null
// 初始化根節點
@@ -28,7 +34,7 @@ fun dfs(preorder: IntArray, inorderMap: Map<Int?, Int?>, i: Int, l: Int, r: Int)
/* 構建二元樹 */
fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
// 初始化雜湊表,儲存 inorder 元素到索引的對映
val inorderMap: MutableMap<Int?, Int?> = HashMap()
val inorderMap = HashMap<Int?, Int?>()
for (i in inorder.indices) {
inorderMap[inorder[i]] = i
}
@@ -40,8 +46,8 @@ fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
fun main() {
val preorder = intArrayOf(3, 9, 2, 1, 7)
val inorder = intArrayOf(9, 3, 1, 2, 7)
println("前序走訪 = " + preorder.contentToString())
println("中序走訪 = " + inorder.contentToString())
println("前序走訪 = ${preorder.contentToString()}")
println("中序走訪 = ${inorder.contentToString()}")
val root = buildTree(preorder, inorder)
println("構建的二元樹為:")
@@ -9,7 +9,7 @@ package chapter_divide_and_conquer.hanota
/* 移動一個圓盤 */
fun move(src: MutableList<Int>, tar: MutableList<Int>) {
// 從 src 頂部拿出一個圓盤
val pan: Int = src.removeAt(src.size - 1)
val pan = src.removeAt(src.size - 1)
// 將圓盤放入 tar 頂部
tar.add(pan)
}
@@ -39,9 +39,9 @@ fun solveHanota(A: MutableList<Int>, B: MutableList<Int>, C: MutableList<Int>) {
/* Driver Code */
fun main() {
// 串列尾部是柱子頂部
val A: MutableList<Int> = ArrayList(mutableListOf(5, 4, 3, 2, 1))
val B: MutableList<Int> = ArrayList()
val C: MutableList<Int> = ArrayList()
val A = mutableListOf(5, 4, 3, 2, 1)
val B = mutableListOf<Int>()
val C = mutableListOf<Int>()
println("初始狀態下:")
println("A = $A")
println("B = $B")
@@ -53,4 +53,4 @@ fun main() {
println("A = $A")
println("B = $B")
println("C = $C")
}
}
@@ -8,13 +8,14 @@ package chapter_dynamic_programming
/* 回溯 */
fun backtrack(
choices: List<Int>,
choices: MutableList<Int>,
state: Int,
n: Int,
res: MutableList<Int>
) {
// 當爬到第 n 階時,方案數量加 1
if (state == n) res[0] = res[0] + 1
if (state == n)
res[0] = res[0] + 1
// 走訪所有選擇
for (choice in choices) {
// 剪枝:不允許越過第 n 階
@@ -29,7 +30,7 @@ fun backtrack(
fun climbingStairsBacktrack(n: Int): Int {
val choices = mutableListOf(1, 2) // 可選擇向上爬 1 階或 2 階
val state = 0 // 從第 0 階開始爬
val res = ArrayList<Int>()
val res = mutableListOf<Int>()
res.add(0) // 使用 res[0] 記錄方案數量
backtrack(choices, state, n, res)
return res[0]
@@ -6,8 +6,6 @@
package chapter_dynamic_programming
import java.util.*
/* 記憶化搜尋 */
fun dfs(i: Int, mem: IntArray): Int {
// 已知 dp[1] 和 dp[2] ,返回之
@@ -25,7 +23,7 @@ fun dfs(i: Int, mem: IntArray): Int {
fun climbingStairsDFSMem(n: Int): Int {
// mem[i] 記錄爬到第 i 階的方案總數,-1 代表無記錄
val mem = IntArray(n + 1)
Arrays.fill(mem, -1)
mem.fill(-1)
return dfs(n, mem)
}
@@ -33,6 +31,6 @@ fun climbingStairsDFSMem(n: Int): Int {
fun main() {
val n = 9
val res: Int = climbingStairsDFSMem(n)
val res = climbingStairsDFSMem(n)
println("$n 階樓梯共有 $res 種方案")
}
@@ -27,9 +27,7 @@ fun climbingStairsDPComp(n: Int): Int {
var a = 1
var b = 2
for (i in 3..n) {
val tmp = b
b += a
a = tmp
b += a.also { a = b }
}
return b
}
@@ -6,7 +6,6 @@
package chapter_dynamic_programming
import java.util.*
import kotlin.math.min
/* 零錢兌換:動態規劃 */
@@ -27,8 +26,7 @@ fun coinChangeDP(coins: IntArray, amt: Int): Int {
dp[i][a] = dp[i - 1][a]
} else {
// 不選和選硬幣 i 這兩種方案的較小值
dp[i][a] = min(dp[i - 1][a].toDouble(), (dp[i][a - coins[i - 1]] + 1).toDouble())
.toInt()
dp[i][a] = min(dp[i - 1][a], dp[i][a - coins[i - 1]] + 1)
}
}
}
@@ -41,7 +39,7 @@ fun coinChangeDPComp(coins: IntArray, amt: Int): Int {
val MAX = amt + 1
// 初始化 dp 表
val dp = IntArray(amt + 1)
Arrays.fill(dp, MAX)
dp.fill(MAX)
dp[0] = 0
// 狀態轉移
for (i in 1..n) {
@@ -51,7 +49,7 @@ fun coinChangeDPComp(coins: IntArray, amt: Int): Int {
dp[a] = dp[a]
} else {
// 不選和選硬幣 i 這兩種方案的較小值
dp[a] = min(dp[a].toDouble(), (dp[a - coins[i - 1]] + 1).toDouble()).toInt()
dp[a] = min(dp[a], dp[a - coins[i - 1]] + 1)
}
}
}
@@ -6,7 +6,6 @@
package chapter_dynamic_programming
import java.util.*
import kotlin.math.min
/* 編輯距離:暴力搜尋 */
@@ -29,7 +28,7 @@ fun editDistanceDFS(
val delete = editDistanceDFS(s, t, i - 1, j)
val replace = editDistanceDFS(s, t, i - 1, j - 1)
// 返回最少編輯步數
return (min(min(insert.toDouble(), delete.toDouble()), replace.toDouble()) + 1).toInt()
return min(min(insert, delete), replace) + 1
}
/* 編輯距離:記憶化搜尋 */
@@ -55,7 +54,7 @@ fun editDistanceDFSMem(
val delete = editDistanceDFSMem(s, t, mem, i - 1, j)
val replace = editDistanceDFSMem(s, t, mem, i - 1, j - 1)
// 記錄並返回最少編輯步數
mem[i][j] = (min(min(insert.toDouble(), delete.toDouble()), replace.toDouble()) + 1).toInt()
mem[i][j] = min(min(insert, delete), replace) + 1
return mem[i][j]
}
@@ -79,11 +78,7 @@ fun editDistanceDP(s: String, t: String): Int {
dp[i][j] = dp[i - 1][j - 1]
} else {
// 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
dp[i][j] =
(min(
min(dp[i][j - 1].toDouble(), dp[i - 1][j].toDouble()),
dp[i - 1][j - 1].toDouble()
) + 1).toInt()
dp[i][j] = min(min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1
}
}
}
@@ -112,7 +107,7 @@ fun editDistanceDPComp(s: String, t: String): Int {
dp[j] = leftup
} else {
// 最少編輯步數 = 插入、刪除、替換這三種操作的最少編輯步數 + 1
dp[j] = (min(min(dp[j - 1].toDouble(), dp[j].toDouble()), leftup.toDouble()) + 1).toInt()
dp[j] = min(min(dp[j - 1], dp[j]), leftup) + 1
}
leftup = temp // 更新為下一輪的 dp[i-1, j-1]
}
@@ -133,7 +128,8 @@ fun main() {
// 記憶化搜尋
val mem = Array(n + 1) { IntArray(m + 1) }
for (row in mem) Arrays.fill(row, -1)
for (row in mem)
row.fill(-1)
res = editDistanceDFSMem(s, t, mem, n, m)
println("$s 更改為 $t 最少需要編輯 $res")
@@ -6,13 +6,12 @@
package chapter_dynamic_programming
import java.util.*
import kotlin.math.max
/* 0-1 背包:暴力搜尋 */
fun knapsackDFS(
wgt: IntArray,
value: IntArray,
_val: IntArray,
i: Int,
c: Int
): Int {
@@ -22,19 +21,19 @@ fun knapsackDFS(
}
// 若超過背包容量,則只能選擇不放入背包
if (wgt[i - 1] > c) {
return knapsackDFS(wgt, value, i - 1, c)
return knapsackDFS(wgt, _val, 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]
val no = knapsackDFS(wgt, _val, i - 1, c)
val yes = knapsackDFS(wgt, _val, i - 1, c - wgt[i - 1]) + _val[i - 1]
// 返回兩種方案中價值更大的那一個
return max(no.toDouble(), yes.toDouble()).toInt()
return max(no, yes)
}
/* 0-1 背包:記憶化搜尋 */
fun knapsackDFSMem(
wgt: IntArray,
value: IntArray,
_val: IntArray,
mem: Array<IntArray>,
i: Int,
c: Int
@@ -49,20 +48,20 @@ fun knapsackDFSMem(
}
// 若超過背包容量,則只能選擇不放入背包
if (wgt[i - 1] > c) {
return knapsackDFSMem(wgt, value, mem, i - 1, c)
return knapsackDFSMem(wgt, _val, 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]
val no = knapsackDFSMem(wgt, _val, mem, i - 1, c)
val yes = knapsackDFSMem(wgt, _val, mem, i - 1, c - wgt[i - 1]) + _val[i - 1]
// 記錄並返回兩種方案中價值更大的那一個
mem[i][c] = max(no.toDouble(), yes.toDouble()).toInt()
mem[i][c] = max(no, yes)
return mem[i][c]
}
/* 0-1 背包:動態規劃 */
fun knapsackDP(
wgt: IntArray,
value: IntArray,
_val: IntArray,
cap: Int
): Int {
val n = wgt.size
@@ -76,8 +75,7 @@ fun knapsackDP(
dp[i][c] = dp[i - 1][c]
} else {
// 不選和選物品 i 這兩種方案的較大值
dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i - 1][c - wgt[i - 1]] + value[i - 1]).toDouble())
.toInt()
dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + _val[i - 1])
}
}
}
@@ -87,7 +85,7 @@ fun knapsackDP(
/* 0-1 背包:空間最佳化後的動態規劃 */
fun knapsackDPComp(
wgt: IntArray,
value: IntArray,
_val: IntArray,
cap: Int
): Int {
val n = wgt.size
@@ -100,7 +98,7 @@ fun knapsackDPComp(
if (wgt[i - 1] <= c) {
// 不選和選物品 i 這兩種方案的較大值
dp[c] =
max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1])
}
}
}
@@ -110,27 +108,27 @@ fun knapsackDPComp(
/* Driver Code */
fun main() {
val wgt = intArrayOf(10, 20, 30, 40, 50)
val value = intArrayOf(50, 120, 150, 210, 240)
val _val = intArrayOf(50, 120, 150, 210, 240)
val cap = 50
val n = wgt.size
// 暴力搜尋
var res = knapsackDFS(wgt, value, n, cap)
var res = knapsackDFS(wgt, _val, n, cap)
println("不超過背包容量的最大物品價值為 $res")
// 記憶化搜尋
val mem = Array(n + 1) { IntArray(cap + 1) }
for (row in mem) {
Arrays.fill(row, -1)
row.fill(-1)
}
res = knapsackDFSMem(wgt, value, mem, n, cap)
res = knapsackDFSMem(wgt, _val, mem, n, cap)
println("不超過背包容量的最大物品價值為 $res")
// 動態規劃
res = knapsackDP(wgt, value, cap)
res = knapsackDP(wgt, _val, cap)
println("不超過背包容量的最大物品價值為 $res")
// 空間最佳化後的動態規劃
res = knapsackDPComp(wgt, value, cap)
res = knapsackDPComp(wgt, _val, cap)
println("不超過背包容量的最大物品價值為 $res")
}
}
@@ -19,7 +19,7 @@ fun minCostClimbingStairsDP(cost: IntArray): Int {
dp[2] = cost[2]
// 狀態轉移:從較小子問題逐步求解較大子問題
for (i in 3..n) {
dp[i] = (min(dp[i - 1].toDouble(), dp[i - 2].toDouble()) + cost[i]).toInt()
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
}
return dp[n]
}
@@ -32,7 +32,7 @@ fun minCostClimbingStairsDPComp(cost: IntArray): Int {
var b = cost[2]
for (i in 3..n) {
val tmp = b
b = (min(a.toDouble(), tmp.toDouble()) + cost[i]).toInt()
b = min(a, tmp) + cost[i]
a = tmp
}
return b
@@ -6,15 +6,10 @@
package chapter_dynamic_programming
import java.util.*
import kotlin.math.min
/* 最小路徑和:暴力搜尋 */
fun minPathSumDFS(
grid: Array<Array<Int>>,
i: Int,
j: Int
): Int {
fun minPathSumDFS(grid: Array<IntArray>, i: Int, j: Int): Int {
// 若為左上角單元格,則終止搜尋
if (i == 0 && j == 0) {
return grid[0][0]
@@ -27,13 +22,13 @@ fun minPathSumDFS(
val up = minPathSumDFS(grid, i - 1, j)
val left = minPathSumDFS(grid, i, j - 1)
// 返回從左上角到 (i, j) 的最小路徑代價
return (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt()
return min(left, up) + grid[i][j]
}
/* 最小路徑和:記憶化搜尋 */
fun minPathSumDFSMem(
grid: Array<Array<Int>>,
mem: Array<Array<Int>>,
grid: Array<IntArray>,
mem: Array<IntArray>,
i: Int,
j: Int
): Int {
@@ -53,12 +48,12 @@ fun minPathSumDFSMem(
val up = minPathSumDFSMem(grid, mem, i - 1, j)
val left = minPathSumDFSMem(grid, mem, i, j - 1)
// 記錄並返回左上角到 (i, j) 的最小路徑代價
mem[i][j] = (min(left.toDouble(), up.toDouble()) + grid[i][j]).toInt()
mem[i][j] = min(left, up) + grid[i][j]
return mem[i][j]
}
/* 最小路徑和:動態規劃 */
fun minPathSumDP(grid: Array<Array<Int>>): Int {
fun minPathSumDP(grid: Array<IntArray>): Int {
val n = grid.size
val m = grid[0].size
// 初始化 dp 表
@@ -75,15 +70,14 @@ fun minPathSumDP(grid: Array<Array<Int>>): Int {
// 狀態轉移:其餘行和列
for (i in 1..<n) {
for (j in 1..<m) {
dp[i][j] =
(min(dp[i][j - 1].toDouble(), dp[i - 1][j].toDouble()) + grid[i][j]).toInt()
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j]
}
}
return dp[n - 1][m - 1]
}
/* 最小路徑和:空間最佳化後的動態規劃 */
fun minPathSumDPComp(grid: Array<Array<Int>>): Int {
fun minPathSumDPComp(grid: Array<IntArray>): Int {
val n = grid.size
val m = grid[0].size
// 初始化 dp 表
@@ -99,7 +93,7 @@ fun minPathSumDPComp(grid: Array<Array<Int>>): Int {
dp[0] = dp[0] + grid[i][0]
// 狀態轉移:其餘列
for (j in 1..<m) {
dp[j] = (min(dp[j - 1].toDouble(), dp[j].toDouble()) + grid[i][j]).toInt()
dp[j] = min(dp[j - 1], dp[j]) + grid[i][j]
}
}
return dp[m - 1]
@@ -108,10 +102,10 @@ fun minPathSumDPComp(grid: Array<Array<Int>>): Int {
/* Driver Code */
fun main() {
val grid = arrayOf(
arrayOf(1, 3, 1, 5),
arrayOf(2, 2, 4, 2),
arrayOf(5, 3, 2, 1),
arrayOf(4, 3, 5, 2)
intArrayOf(1, 3, 1, 5),
intArrayOf(2, 2, 4, 2),
intArrayOf(5, 3, 2, 1),
intArrayOf(4, 3, 5, 2)
)
val n = grid.size
val m = grid[0].size
@@ -121,9 +115,9 @@ fun main() {
println("從左上角到右下角的最小路徑和為 $res")
// 記憶化搜尋
val mem = Array(n) { Array(m) { 0 } }
val mem = Array(n) { IntArray(m) }
for (row in mem) {
Arrays.fill(row, -1)
row.fill(-1)
}
res = minPathSumDFSMem(grid, mem, n - 1, m - 1)
println("從左上角到右下角的最小路徑和為 $res")
@@ -9,11 +9,7 @@ package chapter_dynamic_programming
import kotlin.math.max
/* 完全背包:動態規劃 */
fun unboundedKnapsackDP(
wgt: IntArray,
value: IntArray,
cap: Int
): Int {
fun unboundedKnapsackDP(wgt: IntArray, _val: IntArray, cap: Int): Int {
val n = wgt.size
// 初始化 dp 表
val dp = Array(n + 1) { IntArray(cap + 1) }
@@ -25,8 +21,7 @@ fun unboundedKnapsackDP(
dp[i][c] = dp[i - 1][c]
} else {
// 不選和選物品 i 這兩種方案的較大值
dp[i][c] = max(dp[i - 1][c].toDouble(), (dp[i][c - wgt[i - 1]] + value[i - 1]).toDouble())
.toInt()
dp[i][c] = max(dp[i - 1][c], dp[i][c - wgt[i - 1]] + _val[i - 1])
}
}
}
@@ -36,7 +31,7 @@ fun unboundedKnapsackDP(
/* 完全背包:空間最佳化後的動態規劃 */
fun unboundedKnapsackDPComp(
wgt: IntArray,
value: IntArray,
_val: IntArray,
cap: Int
): Int {
val n = wgt.size
@@ -50,8 +45,7 @@ fun unboundedKnapsackDPComp(
dp[c] = dp[c]
} else {
// 不選和選物品 i 這兩種方案的較大值
dp[c] =
max(dp[c].toDouble(), (dp[c - wgt[i - 1]] + value[i - 1]).toDouble()).toInt()
dp[c] = max(dp[c], dp[c - wgt[i - 1]] + _val[i - 1])
}
}
}
@@ -61,14 +55,14 @@ fun unboundedKnapsackDPComp(
/* Driver Code */
fun main() {
val wgt = intArrayOf(1, 2, 3)
val value = intArrayOf(5, 11, 15)
val _val = intArrayOf(5, 11, 15)
val cap = 4
// 動態規劃
var res = unboundedKnapsackDP(wgt, value, cap)
var res = unboundedKnapsackDP(wgt, _val, cap)
println("不超過背包容量的最大物品價值為 $res")
// 空間最佳化後的動態規劃
res = unboundedKnapsackDPComp(wgt, value, cap)
res = unboundedKnapsackDPComp(wgt, _val, cap)
println("不超過背包容量的最大物品價值為 $res")
}
@@ -11,7 +11,7 @@ import utils.Vertex
/* 基於鄰接表實現的無向圖類別 */
class GraphAdjList(edges: Array<Array<Vertex?>>) {
// 鄰接表,key:頂點,value:該頂點的所有鄰接頂點
val adjList: MutableMap<Vertex, MutableList<Vertex>> = HashMap()
val adjList = HashMap<Vertex, MutableList<Vertex>>()
/* 建構子 */
init {
@@ -70,11 +70,11 @@ class GraphAdjList(edges: Array<Array<Vertex?>>) {
fun print() {
println("鄰接表 =")
for (pair in adjList.entries) {
val tmp = ArrayList<Int>()
val tmp = mutableListOf<Int>()
for (vertex in pair.value) {
tmp.add(vertex.value)
tmp.add(vertex._val)
}
println("${pair.key.value}: $tmp,")
println("${pair.key._val}: $tmp,")
}
}
}
@@ -82,7 +82,7 @@ class GraphAdjList(edges: Array<Array<Vertex?>>) {
/* Driver Code */
fun main() {
/* 初始化無向圖 */
val v: Array<Vertex?> = Vertex.valsToVets(intArrayOf(1, 3, 2, 5, 4))
val v = Vertex.valsToVets(intArrayOf(1, 3, 2, 5, 4))
val edges = arrayOf(
arrayOf(v[0], v[1]),
arrayOf(v[0], v[3]),
@@ -10,8 +10,8 @@ import utils.printMatrix
/* 基於鄰接矩陣實現的無向圖類別 */
class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
val vertices: MutableList<Int> = ArrayList() // 頂點串列,元素代表“頂點值”,索引代表“頂點索引”
val adjMat: MutableList<MutableList<Int>> = ArrayList() // 鄰接矩陣,行列索引對應“頂點索引”
val vertices = mutableListOf<Int>() // 頂點串列,元素代表“頂點值”,索引代表“頂點索引”
val adjMat = mutableListOf<MutableList<Int>>() // 鄰接矩陣,行列索引對應“頂點索引”
/* 建構子 */
init {
@@ -32,12 +32,12 @@ class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
}
/* 新增頂點 */
fun addVertex(value: Int) {
fun addVertex(_val: Int) {
val n = size()
// 向頂點串列中新增新頂點的值
vertices.add(value)
vertices.add(_val)
// 在鄰接矩陣中新增一行
val newRow: MutableList<Int> = mutableListOf()
val newRow = mutableListOf<Int>()
for (j in 0..<n) {
newRow.add(0)
}
@@ -50,7 +50,8 @@ class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
/* 刪除頂點 */
fun removeVertex(index: Int) {
if (index >= size()) throw IndexOutOfBoundsException()
if (index >= size())
throw IndexOutOfBoundsException()
// 在頂點串列中移除索引 index 的頂點
vertices.removeAt(index)
// 在鄰接矩陣中刪除索引 index 的行
@@ -65,7 +66,8 @@ class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
// 參數 i, j 對應 vertices 元素索引
fun addEdge(i: Int, j: Int) {
// 索引越界與相等處理
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
throw IndexOutOfBoundsException()
// 在無向圖中,鄰接矩陣關於主對角線對稱,即滿足 (i, j) == (j, i)
adjMat[i][j] = 1;
adjMat[j][i] = 1;
@@ -75,7 +77,8 @@ class GraphAdjMat(vertices: IntArray, edges: Array<IntArray>) {
// 參數 i, j 對應 vertices 元素索引
fun removeEdge(i: Int, j: Int) {
// 索引越界與相等處理
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException()
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
throw IndexOutOfBoundsException()
adjMat[i][j] = 0;
adjMat[j][i] = 0;
}
@@ -11,24 +11,24 @@ import java.util.*
/* 廣度優先走訪 */
// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
fun graphBFS(graph: GraphAdjList, startVet: Vertex): List<Vertex> {
fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList<Vertex?> {
// 頂點走訪序列
val res: MutableList<Vertex> = ArrayList()
val res = mutableListOf<Vertex?>()
// 雜湊表,用於記錄已被訪問過的頂點
val visited: MutableSet<Vertex> = HashSet()
val visited = HashSet<Vertex>()
visited.add(startVet)
// 佇列用於實現 BFS
val que: Queue<Vertex> = LinkedList()
val que = LinkedList<Vertex>()
que.offer(startVet)
// 以頂點 vet 為起點,迴圈直至訪問完所有頂點
while (!que.isEmpty()) {
val vet = que.poll() // 佇列首頂點出隊
res.add(vet) // 記錄訪問頂點
res.add(vet) // 記錄訪問頂點
// 走訪該頂點的所有鄰接頂點
for (adjVet in graph.adjList[vet]!!) {
if (visited.contains(adjVet)) continue // 跳過已被訪問的頂點
que.offer(adjVet) // 只入列未訪問的頂點
if (visited.contains(adjVet))
continue // 跳過已被訪問的頂點
que.offer(adjVet) // 只入列未訪問的頂點
visited.add(adjVet) // 標記該頂點已被訪問
}
}
@@ -15,11 +15,12 @@ fun dfs(
res: MutableList<Vertex?>,
vet: Vertex?
) {
res.add(vet) // 記錄訪問頂點
res.add(vet) // 記錄訪問頂點
visited.add(vet) // 標記該頂點已被訪問
// 走訪該頂點的所有鄰接頂點
for (adjVet in graph.adjList[vet]!!) {
if (visited.contains(adjVet)) continue // 跳過已被訪問的頂點
if (visited.contains(adjVet))
continue // 跳過已被訪問的頂點
// 遞迴訪問鄰接頂點
dfs(graph, visited, res, adjVet)
}
@@ -27,14 +28,11 @@ fun dfs(
/* 深度優先走訪 */
// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
fun graphDFS(
graph: GraphAdjList,
startVet: Vertex?
): List<Vertex?> {
fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList<Vertex?> {
// 頂點走訪序列
val res: MutableList<Vertex?> = ArrayList()
val res = mutableListOf<Vertex?>()
// 雜湊表,用於記錄已被訪問過的頂點
val visited: MutableSet<Vertex?> = HashSet()
val visited = HashSet<Vertex?>()
dfs(graph, visited, res, startVet)
return res
}
@@ -6,34 +6,28 @@
package chapter_greedy
import java.util.*
/* 物品 */
class Item(
val w: Int, // 物品
val v: Int // 物品價值
val v: Int // 物品價值
)
/* 分數背包:貪婪 */
fun fractionalKnapsack(
wgt: IntArray,
value: IntArray,
c: Int
): Double {
fun fractionalKnapsack(wgt: IntArray, _val: IntArray, c: Int): Double {
// 建立物品串列,包含兩個屬性:重量、價值
var cap = c
val items = arrayOfNulls<Item>(wgt.size)
for (i in wgt.indices) {
items[i] = Item(wgt[i], value[i])
items[i] = Item(wgt[i], _val[i])
}
// 按照單位價值 item.v / item.w 從高到低進行排序
Arrays.sort(items, Comparator.comparingDouble { item: Item -> -(item.v.toDouble() / item.w) })
items.sortBy { item: Item? -> -(item!!.v.toDouble() / item.w) }
// 迴圈貪婪選擇
var res = 0.0
for (item in items) {
if (item!!.w <= cap) {
// 若剩餘容量充足,則將當前物品整個裝進背包
res += item.v.toDouble()
res += item.v
cap -= item.w
} else {
// 若剩餘容量不足,則將當前物品的一部分裝進背包
@@ -48,10 +42,10 @@ fun fractionalKnapsack(
/* Driver Code */
fun main() {
val wgt = intArrayOf(10, 20, 30, 40, 50)
val values = intArrayOf(50, 120, 150, 210, 240)
val _val = intArrayOf(50, 120, 150, 210, 240)
val cap = 50
// 貪婪演算法
val res = fractionalKnapsack(wgt, values, cap)
val res = fractionalKnapsack(wgt, _val, cap)
println("不超過背包容量的最大物品價值為 $res")
}
@@ -19,8 +19,8 @@ fun maxCapacity(ht: IntArray): Int {
// 迴圈貪婪選擇,直至兩板相遇
while (i < j) {
// 更新最大容量
val cap = (min(ht[i].toDouble(), ht[j].toDouble()) * (j - i)).toInt()
res = max(res.toDouble(), cap.toDouble()).toInt()
val cap = min(ht[i], ht[j]) * (j - i)
res = max(res, cap)
// 向內移動短板
if (ht[i] < ht[j]) {
i++
@@ -19,14 +19,14 @@ fun maxProductCutting(n: Int): Int {
val b = n % 3
if (b == 1) {
// 當餘數為 1 時,將一對 1 * 3 轉化為 2 * 2
return 3.0.pow((a - 1).toDouble()).toInt() * 2 * 2
return 3.0.pow((a - 1)).toInt() * 2 * 2
}
if (b == 2) {
// 當餘數為 2 時,不做處理
return 3.0.pow(a.toDouble()).toInt() * 2 * 2
return 3.0.pow(a).toInt() * 2 * 2
}
// 當餘數為 0 時,不做處理
return 3.0.pow(a.toDouble()).toInt()
return 3.0.pow(a).toInt()
}
/* Driver Code */
@@ -36,4 +36,4 @@ fun main() {
// 貪婪演算法
val res = maxProductCutting(n)
println("最大切分乘積為 $res")
}
}
@@ -9,20 +9,14 @@ package chapter_hashing
/* 鍵值對 */
class Pair(
var key: Int,
var value: String
var _val: String
)
/* 基於陣列實現的雜湊表 */
class ArrayHashMap {
// 初始化陣列,包含 100 個桶
private val buckets = arrayOfNulls<Pair>(100)
init {
// 初始化陣列,包含 100 個桶
for (i in 0..<100) {
buckets[i] = null
}
}
/* 雜湊函式 */
fun hashFunc(key: Int): Int {
val index = key % 100
@@ -33,12 +27,12 @@ class ArrayHashMap {
fun get(key: Int): String? {
val index = hashFunc(key)
val pair = buckets[index] ?: return null
return pair.value
return pair._val
}
/* 新增操作 */
fun put(key: Int, value: String) {
val pair = Pair(key, value)
fun put(key: Int, _val: String) {
val pair = Pair(key, _val)
val index = hashFunc(key)
buckets[index] = pair
}
@@ -52,27 +46,29 @@ class ArrayHashMap {
/* 獲取所有鍵值對 */
fun pairSet(): MutableList<Pair> {
val pairSet = ArrayList<Pair>()
val pairSet = mutableListOf<Pair>()
for (pair in buckets) {
if (pair != null) pairSet.add(pair)
if (pair != null)
pairSet.add(pair)
}
return pairSet
}
/* 獲取所有鍵 */
fun keySet(): MutableList<Int> {
val keySet = ArrayList<Int>()
val keySet = mutableListOf<Int>()
for (pair in buckets) {
if (pair != null) keySet.add(pair.key)
if (pair != null)
keySet.add(pair.key)
}
return keySet
}
/* 獲取所有值 */
fun valueSet(): MutableList<String> {
val valueSet = ArrayList<String>()
val valueSet = mutableListOf<String>()
for (pair in buckets) {
pair?.let { valueSet.add(it.value) }
pair?.let { valueSet.add(it._val) }
}
return valueSet
}
@@ -81,8 +77,8 @@ class ArrayHashMap {
fun print() {
for (kv in pairSet()) {
val key = kv.key
val value = kv.value
println("${key}->${value}")
val _val = kv._val
println("${key} -> ${_val}")
}
}
}
@@ -104,7 +100,7 @@ fun main() {
/* 查詢操作 */
// 向雜湊表中輸入鍵 key ,得到值 value
val name: String? = map.get(15937)
val name = map.get(15937)
println("\n輸入學號 15937 ,查詢到姓名 $name")
/* 刪除操作 */
@@ -114,16 +110,16 @@ fun main() {
map.print()
/* 走訪雜湊表 */
println("\n走訪鍵值對 Key->Value")
println("\n走訪鍵值對 Key -> Value")
for (kv in map.pairSet()) {
println("${kv.key} -> ${kv.value}")
println("${kv.key} -> ${kv._val}")
}
println("\n單獨走訪鍵 Key")
for (key in map.keySet()) {
println(key)
}
println("\n單獨走訪值 Value")
for (value in map.valueSet()) {
println(value)
for (_val in map.valueSet()) {
println(_val)
}
}
}
@@ -11,15 +11,15 @@ import utils.ListNode
/* Driver Code */
fun main() {
val num = 3
val hashNum = Integer.hashCode(num)
val hashNum = num.hashCode()
println("整數 $num 的雜湊值為 $hashNum")
val bol = true
val hashBol = Boolean.hashCode()
val hashBol = bol.hashCode()
println("布林量 $bol 的雜湊值為 $hashBol")
val dec = 3.14159
val hashDec = java.lang.Double.hashCode(dec)
val hashDec = dec.hashCode()
println("小數 $dec 的雜湊值為 $hashDec")
val str = "Hello 演算法"
@@ -11,7 +11,7 @@ import utils.printHashMap
/* Driver Code */
fun main() {
/* 初始化雜湊表 */
val map: MutableMap<Int, String> = HashMap()
val map = HashMap<Int, String>()
/* 新增操作 */
// 在雜湊表中新增鍵值對 (key, value)
@@ -44,7 +44,7 @@ fun main() {
println(key)
}
println("\n單獨走訪值 Value")
for (value in map.values) {
println(value)
for (_val in map.values) {
println(_val)
}
}
@@ -20,7 +20,7 @@ class HashMapChaining() {
capacity = 4
loadThres = 2.0 / 3.0
extendRatio = 2
buckets = ArrayList(capacity)
buckets = mutableListOf()
for (i in 0..<capacity) {
buckets.add(mutableListOf())
}
@@ -42,14 +42,14 @@ class HashMapChaining() {
val bucket = buckets[index]
// 走訪桶,若找到 key ,則返回對應 val
for (pair in bucket) {
if (pair.key == key) return pair.value
if (pair.key == key) return pair._val
}
// 若未找到 key ,則返回 null
return null
}
/* 新增操作 */
fun put(key: Int, value: String) {
fun put(key: Int, _val: String) {
// 當負載因子超過閾值時,執行擴容
if (loadFactor() > loadThres) {
extend()
@@ -59,12 +59,12 @@ class HashMapChaining() {
// 走訪桶,若遇到指定 key ,則更新對應 val 並返回
for (pair in bucket) {
if (pair.key == key) {
pair.value = value
pair._val = _val
return
}
}
// 若無該 key ,則將鍵值對新增至尾部
val pair = Pair(key, value)
val pair = Pair(key, _val)
bucket.add(pair)
size++
}
@@ -98,7 +98,7 @@ class HashMapChaining() {
// 將鍵值對從原雜湊表搬運至新雜湊表
for (bucket in bucketsTmp) {
for (pair in bucket) {
put(pair.key, pair.value)
put(pair.key, pair._val)
}
}
}
@@ -109,7 +109,7 @@ class HashMapChaining() {
val res = mutableListOf<String>()
for (pair in bucket) {
val k = pair.key
val v = pair.value
val v = pair._val
res.add("$k -> $v")
}
println(res)
@@ -142,4 +142,4 @@ fun main() {
map.remove(12836)
println("\n刪除 12836 後,雜湊表為\nKey -> Value")
map.print()
}
}
@@ -8,16 +8,21 @@ package chapter_hashing
/* 開放定址雜湊表 */
class HashMapOpenAddressing {
private var size: Int = 0 // 鍵值對數量
private var capacity = 4 // 雜湊表容量
private val loadThres: Double = 2.0 / 3.0 // 觸發擴容的負載因子閾值
private val extendRatio = 2 // 擴容倍數
private var buckets: Array<Pair?> // 桶陣列
private val TOMBSTONE = Pair(-1, "-1") // 刪除標記
private var size: Int // 鍵值對數量
private var capacity: Int // 雜湊表容量
private val loadThres: Double // 觸發擴容的負載因子閾值
private val extendRatio: Int // 擴容倍數
private var buckets: Array<Pair?> // 桶陣列
private val TOMBSTONE: Pair // 刪除標記
/* 建構子 */
init {
size = 0
capacity = 4
loadThres = 2.0 / 3.0
extendRatio = 2
buckets = arrayOfNulls(capacity)
TOMBSTONE = Pair(-1, "-1")
}
/* 雜湊函式 */
@@ -63,14 +68,14 @@ class HashMapOpenAddressing {
val index = findBucket(key)
// 若找到鍵值對,則返回對應 val
if (buckets[index] != null && buckets[index] != TOMBSTONE) {
return buckets[index]?.value
return buckets[index]?._val
}
// 若鍵值對不存在,則返回 null
return null
}
/* 新增操作 */
fun put(key: Int, value: String) {
fun put(key: Int, _val: String) {
// 當負載因子超過閾值時,執行擴容
if (loadFactor() > loadThres) {
extend()
@@ -79,11 +84,11 @@ class HashMapOpenAddressing {
val index = findBucket(key)
// 若找到鍵值對,則覆蓋 val 並返回
if (buckets[index] != null && buckets[index] != TOMBSTONE) {
buckets[index]!!.value = value
buckets[index]!!._val = _val
return
}
// 若鍵值對不存在,則新增該鍵值對
buckets[index] = Pair(key, value)
buckets[index] = Pair(key, _val)
size++
}
@@ -109,7 +114,7 @@ class HashMapOpenAddressing {
// 將鍵值對從原雜湊表搬運至新雜湊表
for (pair in bucketsTmp) {
if (pair != null && pair != TOMBSTONE) {
put(pair.key, pair.value)
put(pair.key, pair._val)
}
}
}
@@ -122,7 +127,7 @@ class HashMapOpenAddressing {
} else if (pair == TOMBSTONE) {
println("TOMESTOME")
} else {
println("${pair.key} -> ${pair.value}")
println("${pair.key} -> ${pair._val}")
}
}
}
@@ -6,7 +6,7 @@
package chapter_hashing
const val MODULUS = 10_0000_0007
const val MODULUS = 1000000007
/* 加法雜湊 */
fun addHash(key: String): Int {
@@ -48,7 +48,7 @@ fun rotHash(key: String): Int {
fun main() {
val key = "Hello 演算法"
var hash: Int = addHash(key)
var hash = addHash(key)
println("加法雜湊值為 $hash")
hash = mulHash(key)
+6 -6
View File
@@ -9,15 +9,15 @@ package chapter_heap
import utils.printHeap
import java.util.*
fun testPush(heap: Queue<Int>, value: Int) {
heap.offer(value) // 元素入堆積
print("\n元素 $value 入堆積後\n")
fun testPush(heap: Queue<Int>, _val: Int) {
heap.offer(_val) // 元素入堆積
print("\n元素 $_val 入堆積後\n")
printHeap(heap)
}
fun testPop(heap: Queue<Int>) {
val value = heap.poll() // 堆積頂元素出堆積
print("\n堆積頂元素 $value 出堆積後\n")
val _val = heap.poll() // 堆積頂元素出堆積
print("\n堆積頂元素 $_val 出堆積後\n")
printHeap(heap)
}
@@ -25,7 +25,7 @@ fun testPop(heap: Queue<Int>) {
fun main() {
/* 初始化堆積 */
// 初始化小頂堆積
val minHeap: PriorityQueue<Int>
var minHeap = PriorityQueue<Int>()
// 初始化大頂堆積(使用 lambda 表示式修改 Comparator 即可)
val maxHeap = PriorityQueue { a: Int, b: Int -> b - a }
+12 -11
View File
@@ -10,13 +10,14 @@ import utils.printHeap
import java.util.*
/* 大頂堆積 */
class MaxHeap(nums: List<Int>?) {
class MaxHeap(nums: MutableList<Int>?) {
// 使用串列而非陣列,這樣無須考慮擴容問題
// 將串列元素原封不動新增進堆積
private val maxHeap = ArrayList(nums!!)
private val maxHeap = mutableListOf<Int>()
/* 建構子,根據輸入串列建堆積 */
init {
// 將串列元素原封不動新增進堆積
maxHeap.addAll(nums!!)
// 堆積化除葉節點以外的其他所有節點
for (i in parent(size() - 1) downTo 0) {
siftDown(i)
@@ -60,9 +61,9 @@ class MaxHeap(nums: List<Int>?) {
}
/* 元素入堆積 */
fun push(value: Int) {
fun push(_val: Int) {
// 新增節點
maxHeap.add(value)
maxHeap.add(_val)
// 從底至頂堆積化
siftUp(size() - 1)
}
@@ -90,11 +91,11 @@ class MaxHeap(nums: List<Int>?) {
// 交換根節點與最右葉節點(交換首元素與尾元素)
swap(0, size() - 1)
// 刪除節點
val value = maxHeap.removeAt(size() - 1)
val _val = maxHeap.removeAt(size() - 1)
// 從頂至底堆積化
siftDown(0)
// 返回堆積頂元素
return value
return _val
}
/* 從節點 i 開始,從頂至底堆積化 */
@@ -137,9 +138,9 @@ fun main() {
print("\n堆積頂元素為 $peek\n")
/* 元素入堆積 */
val value = 7
maxHeap.push(value)
print("\n元素 $value 入堆積後\n")
val _val = 7
maxHeap.push(_val)
print("\n元素 $_val 入堆積後\n")
maxHeap.print()
/* 堆積頂元素出堆積 */
@@ -154,4 +155,4 @@ fun main() {
/* 判斷堆積是否為空 */
val isEmpty = maxHeap.isEmpty()
print("\n堆積是否為空 $isEmpty\n")
}
}
@@ -7,18 +7,17 @@
package chapter_searching
import utils.ListNode
import java.util.HashMap
/* 雜湊查詢(陣列) */
fun hashingSearchArray(map: Map<Int?, Int>, target: Int): Int {
// 雜湊表的 key: 目標元素,value: 索引
// 雜湊表的 key: 目標元素,_val: 索引
// 若雜湊表中無此 key ,返回 -1
return map.getOrDefault(target, -1)
}
/* 雜湊查詢(鏈結串列) */
fun hashingSearchLinkedList(map: Map<Int?, ListNode?>, target: Int): ListNode? {
// 雜湊表的 key: 目標節點值,value: 節點物件
// 雜湊表的 key: 目標節點值,_val: 節點物件
// 若雜湊表中無此 key ,返回 null
return map.getOrDefault(target, null)
}
@@ -32,7 +31,7 @@ fun main() {
// 初始化雜湊表
val map = HashMap<Int?, Int>()
for (i in nums.indices) {
map[nums[i]] = i // key: 元素,value: 索引
map[nums[i]] = i // key: 元素,_val: 索引
}
val index = hashingSearchArray(map, target)
println("目標元素 3 的索引 = $index")
@@ -42,7 +41,7 @@ fun main() {
// 初始化雜湊表
val map1 = HashMap<Int?, ListNode?>()
while (head != null) {
map1[head.value] = head // key: 節點值,value: 節點
map1[head._val] = head // key: 節點值,_val: 節點
head = head.next
}
val node = hashingSearchLinkedList(map1, target)
@@ -26,7 +26,7 @@ fun linearSearchLinkedList(h: ListNode?, target: Int): ListNode? {
var head = h
while (head != null) {
// 找到目標節點,返回之
if (head.value == target)
if (head._val == target)
return head
head = head.next
}
@@ -14,7 +14,7 @@ fun bubbleSort(nums: IntArray) {
for (j in 0..<i) {
if (nums[j] > nums[j + 1]) {
// 交換 nums[j] 與 nums[j + 1]
nums[j] = nums[j+1].also { nums[j+1] = nums[j] }
nums[j] = nums[j + 1].also { nums[j + 1] = nums[j] }
}
}
}
@@ -6,15 +6,13 @@
package chapter_sorting
import kotlin.collections.ArrayList
/* 桶排序 */
fun bucketSort(nums: FloatArray) {
// 初始化 k = n/2 個桶,預期向每個桶分配 2 個元素
val k = nums.size / 2
val buckets = ArrayList<ArrayList<Float>>()
val buckets = mutableListOf<MutableList<Float>>()
for (i in 0..<k) {
buckets.add(ArrayList())
buckets.add(mutableListOf())
}
// 1. 將陣列元素分配到各個桶中
for (num in nums) {
@@ -14,7 +14,7 @@ fun countingSortNaive(nums: IntArray) {
// 1. 統計陣列最大元素 m
var m = 0
for (num in nums) {
m = max(m.toDouble(), num.toDouble()).toInt()
m = max(m, num)
}
// 2. 統計各數字的出現次數
// counter[num] 代表 num 的出現次數
@@ -40,7 +40,7 @@ fun countingSort(nums: IntArray) {
// 1. 統計陣列最大元素 m
var m = 0
for (num in nums) {
m = max(m.toDouble(), num.toDouble()).toInt()
m = max(m, num)
}
// 2. 統計各數字的出現次數
// counter[num] 代表 num 的出現次數
@@ -14,10 +14,13 @@ fun siftDown(nums: IntArray, n: Int, li: Int) {
val l = 2 * i + 1
val r = 2 * i + 2
var ma = i
if (l < n && nums[l] > nums[ma]) ma = l
if (r < n && nums[r] > nums[ma]) ma = r
if (l < n && nums[l] > nums[ma])
ma = l
if (r < n && nums[r] > nums[ma])
ma = r
// 若節點 i 最大或索引 l, r 越界,則無須繼續堆積化,跳出
if (ma == i) break
if (ma == i)
break
// 交換兩節點
nums[i] = nums[ma].also { nums[ma] = nums[i] }
// 迴圈向下堆積化
@@ -12,7 +12,7 @@ fun insertionSort(nums: IntArray) {
for (i in nums.indices) {
val base = nums[i]
var j = i - 1
// 內迴圈: 將 base 插入到已排序部分的正確位置
// 內迴圈將 base 插入到已排序區間 [0, i-1] 中的正確位置
while (j >= 0 && nums[j] > base) {
nums[j + 1] = nums[j] // 將 nums[j] 向右移動一位
j--
@@ -17,8 +17,10 @@ fun merge(nums: IntArray, left: Int, mid: Int, right: Int) {
var k = 0
// 當左右子陣列都還有元素時,進行比較並將較小的元素複製到臨時陣列中
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) tmp[k++] = nums[i++]
else tmp[k++] = nums[j++]
if (nums[i] <= nums[j])
tmp[k++] = nums[i++]
else
tmp[k++] = nums[j++]
}
// 將左子陣列和右子陣列的剩餘元素複製到臨時陣列中
while (i <= mid) {
@@ -20,7 +20,7 @@ fun countingSortDigit(nums: IntArray, exp: Int) {
// 統計 0~9 各數字的出現次數
for (i in 0..<n) {
val d = digit(nums[i], exp) // 獲取 nums[i] 第 k 位,記為 d
counter[d]++ // 統計數字 d 的出現次數
counter[d]++ // 統計數字 d 的出現次數
}
// 求前綴和,將“出現個數”轉換為“陣列索引”
for (i in 1..9) {
@@ -31,11 +31,12 @@ fun countingSortDigit(nums: IntArray, exp: Int) {
for (i in n - 1 downTo 0) {
val d = digit(nums[i], exp)
val j = counter[d] - 1 // 獲取 d 在陣列中的索引 j
res[j] = nums[i] // 將當前元素填入索引 j
counter[d]-- // 將 d 的數量減 1
res[j] = nums[i] // 將當前元素填入索引 j
counter[d]-- // 將 d 的數量減 1
}
// 使用結果覆蓋原陣列 nums
for (i in 0..<n) nums[i] = res[i]
for (i in 0..<n)
nums[i] = res[i]
}
/* 基數排序 */
@@ -14,7 +14,8 @@ fun selectionSort(nums: IntArray) {
var k = i
// 內迴圈:找到未排序區間內的最小元素
for (j in i + 1..<n) {
if (nums[j] < nums[k]) k = j // 記錄最小元素的索引
if (nums[j] < nums[k])
k = j // 記錄最小元素的索引
}
// 將該最小元素與未排序區間的首個元素交換
nums[i] = nums[k].also { nums[k] = nums[i] }
@@ -7,10 +7,11 @@
package chapter_stack_and_queue
/* 基於環形陣列實現的雙向佇列 */
/* 建構子 */
class ArrayDeque(capacity: Int) {
private var nums = IntArray(capacity) // 用於儲存雙向佇列元素的陣列
private var front = 0 // 佇列首指標,指向佇列首元素
private var queSize = 0 // 雙向佇列長度
private var nums: IntArray = IntArray(capacity) // 用於儲存雙向佇列元素的陣列
private var front: Int = 0 // 佇列首指標,指向佇列首元素
private var queSize: Int = 0 // 雙向佇列長度
/* 獲取雙向佇列的容量 */
fun capacity(): Int {
@@ -71,7 +72,7 @@ class ArrayDeque(capacity: Int) {
return num
}
/* 訪問佇列尾元素 */
/* 佇列尾出列 */
fun popLast(): Int {
val num = peekLast()
queSize--
@@ -8,9 +8,9 @@ package chapter_stack_and_queue
/* 基於環形陣列實現的佇列 */
class ArrayQueue(capacity: Int) {
private val nums = IntArray(capacity) // 用於儲存佇列元素的陣列
private var front = 0 // 佇列首指標,指向佇列首元素
private var queSize = 0 // 佇列長度
private val nums: IntArray = IntArray(capacity) // 用於儲存佇列元素的陣列
private var front: Int = 0 // 佇列首指標,指向佇列首元素
private var queSize: Int = 0 // 佇列長度
/* 獲取佇列的容量 */
fun capacity(): Int {
@@ -9,7 +9,7 @@ package chapter_stack_and_queue
/* 基於陣列實現的堆疊 */
class ArrayStack {
// 初始化串列(動態陣列)
private val stack = ArrayList<Int>()
private val stack = mutableListOf<Int>()
/* 獲取堆疊的長度 */
fun size(): Int {
@@ -40,7 +40,7 @@ class ArrayStack {
/* 將 List 轉化為 Array 並返回 */
fun toArray(): Array<Any> {
return stack.toArray()
return stack.toTypedArray()
}
}
@@ -63,7 +63,7 @@ fun main() {
/* 元素出堆疊 */
val pop = stack.pop()
println("出堆疊元素 pop = ${pop},出堆疊後 stack = ${stack.toArray().contentToString()}")
println("出堆疊元素 pop = $pop,出堆疊後 stack = ${stack.toArray().contentToString()}")
/* 獲取堆疊的長度 */
val size = stack.size()
@@ -7,7 +7,7 @@
package chapter_stack_and_queue
/* 雙向鏈結串列節點 */
class ListNode(var value: Int) {
class ListNode(var _val: Int) {
// 節點值
var next: ListNode? = null // 後繼節點引用
var prev: ListNode? = null // 前驅節點引用
@@ -15,9 +15,9 @@ class ListNode(var value: Int) {
/* 基於雙向鏈結串列實現的雙向佇列 */
class LinkedListDeque {
private var front: ListNode? = null // 頭節點 front ,尾節點 rear
private var rear: ListNode? = null
private var queSize = 0 // 雙向佇列的長度
private var front: ListNode? = null // 頭節點 front
private var rear: ListNode? = null // 尾節點 rear
private var queSize: Int = 0 // 雙向佇列的長度
/* 獲取雙向佇列的長度 */
fun size(): Int {
@@ -64,12 +64,12 @@ class LinkedListDeque {
/* 出列操作 */
fun pop(isFront: Boolean): Int {
if (isEmpty()) throw IndexOutOfBoundsException()
val value: Int
if (isEmpty())
throw IndexOutOfBoundsException()
val _val: Int
// 佇列首出列操作
if (isFront) {
value = front!!.value // 暫存頭節點值
_val = front!!._val // 暫存頭節點值
// 刪除頭節點
val fNext = front!!.next
if (fNext != null) {
@@ -79,7 +79,7 @@ class LinkedListDeque {
front = fNext // 更新頭節點
// 佇列尾出列操作
} else {
value = rear!!.value // 暫存尾節點值
_val = rear!!._val // 暫存尾節點值
// 刪除尾節點
val rPrev = rear!!.prev
if (rPrev != null) {
@@ -89,7 +89,7 @@ class LinkedListDeque {
rear = rPrev // 更新尾節點
}
queSize-- // 更新佇列長度
return value
return _val
}
/* 佇列首出列 */
@@ -104,17 +104,14 @@ class LinkedListDeque {
/* 訪問佇列首元素 */
fun peekFirst(): Int {
if (isEmpty()) {
throw IndexOutOfBoundsException()
}
return front!!.value
if (isEmpty()) throw IndexOutOfBoundsException()
return front!!._val
}
/* 訪問佇列尾元素 */
fun peekLast(): Int {
if (isEmpty()) throw IndexOutOfBoundsException()
return rear!!.value
return rear!!._val
}
/* 返回陣列用於列印 */
@@ -122,7 +119,7 @@ class LinkedListDeque {
var node = front
val res = IntArray(size())
for (i in res.indices) {
res[i] = node!!.value
res[i] = node!!._val
node = node.next
}
return res
@@ -52,7 +52,7 @@ class LinkedListQueue(
/* 訪問佇列首元素 */
fun peek(): Int {
if (isEmpty()) throw IndexOutOfBoundsException()
return front!!.value
return front!!._val
}
/* 將鏈結串列轉化為 Array 並返回 */
@@ -60,7 +60,7 @@ class LinkedListQueue(
var node = front
val res = IntArray(size())
for (i in res.indices) {
res[i] = node!!.value
res[i] = node!!._val
node = node.next
}
return res
@@ -95,4 +95,4 @@ fun main() {
/* 判斷佇列是否為空 */
val isEmpty = queue.isEmpty()
println("佇列是否為空 = $isEmpty")
}
}
@@ -41,7 +41,7 @@ class LinkedListStack(
/* 訪問堆疊頂元素 */
fun peek(): Int? {
if (isEmpty()) throw IndexOutOfBoundsException()
return stackPeek?.value
return stackPeek?._val
}
/* 將 List 轉化為 Array 並返回 */
@@ -49,7 +49,7 @@ class LinkedListStack(
var node = stackPeek
val res = IntArray(size())
for (i in res.size - 1 downTo 0) {
res[i] = node?.value!!
res[i] = node?._val!!
node = node.next
}
return res
@@ -10,14 +10,15 @@ import utils.TreeNode
import utils.printTree
/* 陣列表示下的二元樹類別 */
class ArrayBinaryTree(private val tree: List<Int?>) {
/* 建構子 */
class ArrayBinaryTree(private val tree: MutableList<Int?>) {
/* 串列容量 */
fun size(): Int {
return tree.size
}
/* 獲取索引為 i 節點的值 */
fun value(i: Int): Int? {
fun _val(i: Int): Int? {
// 若索引越界,則返回 null ,代表空位
if (i < 0 || i >= size()) return null
return tree[i]
@@ -39,11 +40,12 @@ class ArrayBinaryTree(private val tree: List<Int?>) {
}
/* 層序走訪 */
fun levelOrder(): List<Int?> {
val res = ArrayList<Int?>()
fun levelOrder(): MutableList<Int?> {
val res = mutableListOf<Int?>()
// 直接走訪陣列
for (i in 0..<size()) {
if (value(i) != null) res.add(value(i))
if (_val(i) != null)
res.add(_val(i))
}
return res
}
@@ -51,34 +53,38 @@ class ArrayBinaryTree(private val tree: List<Int?>) {
/* 深度優先走訪 */
fun dfs(i: Int, order: String, res: MutableList<Int?>) {
// 若為空位,則返回
if (value(i) == null) return
if (_val(i) == null)
return
// 前序走訪
if ("pre" == order) res.add(value(i))
if ("pre" == order)
res.add(_val(i))
dfs(left(i), order, res)
// 中序走訪
if ("in" == order) res.add(value(i))
if ("in" == order)
res.add(_val(i))
dfs(right(i), order, res)
// 後序走訪
if ("post" == order) res.add(value(i))
if ("post" == order)
res.add(_val(i))
}
/* 前序走訪 */
fun preOrder(): List<Int?> {
val res = ArrayList<Int?>()
fun preOrder(): MutableList<Int?> {
val res = mutableListOf<Int?>()
dfs(0, "pre", res)
return res
}
/* 中序走訪 */
fun inOrder(): List<Int?> {
val res = ArrayList<Int?>()
fun inOrder(): MutableList<Int?> {
val res = mutableListOf<Int?>()
dfs(0, "in", res)
return res
}
/* 後序走訪 */
fun postOrder(): List<Int?> {
val res = ArrayList<Int?>()
fun postOrder(): MutableList<Int?> {
val res = mutableListOf<Int?>()
dfs(0, "post", res)
return res
}
@@ -105,10 +111,10 @@ fun main() {
val l = abt.left(i)
val r = abt.right(i)
val p = abt.parent(i)
println("當前節點的索引為 $i ,值為 ${abt.value(i)}")
println("其左子節點的索引為 $l ,值為 ${abt.value(l)}")
println("其右子節點的索引為 $r ,值為 ${abt.value(r)}")
println("其父節點的索引為 $p ,值為 ${abt.value(p)}")
println("當前節點的索引為 $i ,值為 ${abt._val(i)}")
println("其左子節點的索引為 $l ,值為 ${abt._val(l)}")
println("其右子節點的索引為 $r ,值為 ${abt._val(r)}")
println("其父節點的索引為 $p ,值為 ${abt._val(p)}")
// 走訪樹
var res = abt.levelOrder()
+45 -30
View File
@@ -23,7 +23,7 @@ class AVLTree {
/* 更新節點高度 */
private fun updateHeight(node: TreeNode?) {
// 節點高度等於最高子樹高度 + 1
node?.height = (max(height(node?.left).toDouble(), height(node?.right).toDouble()) + 1).toInt()
node?.height = max(height(node?.left), height(node?.right)) + 1
}
/* 獲取平衡因子 */
@@ -93,20 +93,22 @@ class AVLTree {
}
/* 插入節點 */
fun insert(value: Int) {
root = insertHelper(root, value)
fun insert(_val: Int) {
root = insertHelper(root, _val)
}
/* 遞迴插入節點(輔助方法) */
private fun insertHelper(n: TreeNode?, value: Int): TreeNode {
private fun insertHelper(n: TreeNode?, _val: Int): TreeNode {
if (n == null)
return TreeNode(value)
return TreeNode(_val)
var node = n
/* 1. 查詢插入位置並插入節點 */
if (value < node.value) node.left = insertHelper(node.left, value)
else if (value > node.value) node.right = insertHelper(node.right, value)
else return node // 重複節點不插入,直接返回
if (_val < node._val)
node.left = insertHelper(node.left, _val)
else if (_val > node._val)
node.right = insertHelper(node.right, _val)
else
return node // 重複節點不插入,直接返回
updateHeight(node) // 更新節點高度
/* 2. 執行旋轉操作,使該子樹重新恢復平衡 */
node = rotate(node)
@@ -115,30 +117,38 @@ class AVLTree {
}
/* 刪除節點 */
fun remove(value: Int) {
root = removeHelper(root, value)
fun remove(_val: Int) {
root = removeHelper(root, _val)
}
/* 遞迴刪除節點(輔助方法) */
private fun removeHelper(n: TreeNode?, value: Int): TreeNode? {
private fun removeHelper(n: TreeNode?, _val: Int): TreeNode? {
var node = n ?: return null
/* 1. 查詢節點並刪除 */
if (value < node.value) node.left = removeHelper(node.left, value)
else if (value > node.value) node.right = removeHelper(node.right, value)
if (_val < node._val)
node.left = removeHelper(node.left, _val)
else if (_val > node._val)
node.right = removeHelper(node.right, _val)
else {
if (node.left == null || node.right == null) {
val child = if (node.left != null) node.left else node.right
val child = if (node.left != null)
node.left
else
node.right
// 子節點數量 = 0 ,直接刪除 node 並返回
if (child == null) return null
else node = child
if (child == null)
return null
// 子節點數量 = 1 ,直接刪除 node
else
node = child
} else {
// 子節點數量 = 2 ,則將中序走訪的下個節點刪除,並用該節點替換當前節點
var temp = node.right
while (temp!!.left != null) {
temp = temp.left
}
node.right = removeHelper(node.right, temp.value)
node.value = temp.value
node.right = removeHelper(node.right, temp._val)
node._val = temp._val
}
}
updateHeight(node) // 更新節點高度
@@ -149,29 +159,34 @@ class AVLTree {
}
/* 查詢節點 */
fun search(value: Int): TreeNode? {
fun search(_val: Int): TreeNode? {
var cur = root
// 迴圈查詢,越過葉節點後跳出
while (cur != null) {
// 目標節點在 cur 的右子樹中
cur = if (cur.value < value) cur.right!!
else (if (cur.value > value) cur.left
else break)!!
cur = if (cur._val < _val)
cur.right!!
// 目標節點在 cur 的左子樹中
else if (cur._val > _val)
cur.left
// 找到目標節點,跳出迴圈
else
break
}
// 返回目標節點
return cur
}
}
fun testInsert(tree: AVLTree, value: Int) {
tree.insert(value)
println("\n插入節點 $value 後,AVL 樹為")
fun testInsert(tree: AVLTree, _val: Int) {
tree.insert(_val)
println("\n插入節點 $_val 後,AVL 樹為")
printTree(tree.root)
}
fun testRemove(tree: AVLTree, value: Int) {
tree.remove(value)
println("\n刪除節點 $value 後,AVL 樹為")
fun testRemove(tree: AVLTree, _val: Int) {
tree.remove(_val)
println("\n刪除節點 $_val 後,AVL 樹為")
printTree(tree.root)
}
@@ -204,5 +219,5 @@ fun main() {
/* 查詢節點 */
val node = avlTree.search(7)
println("\n 查詢到的節點物件為 $node,節點值 = ${node?.value}")
println("\n 查詢到的節點物件為 $node,節點值 = ${node?._val}")
}
@@ -11,6 +11,7 @@ import utils.printTree
/* 二元搜尋樹 */
class BinarySearchTree {
// 初始化空樹
private var root: TreeNode? = null
/* 獲取二元樹根節點 */
@@ -24,11 +25,14 @@ class BinarySearchTree {
// 迴圈查詢,越過葉節點後跳出
while (cur != null) {
// 目標節點在 cur 的右子樹中
cur = if (cur.value < num) cur.right
cur = if (cur._val < num)
cur.right
// 目標節點在 cur 的左子樹中
else if (cur.value > num) cur.left
else if (cur._val > num)
cur.left
// 找到目標節點,跳出迴圈
else break
else
break
}
// 返回目標節點
return cur
@@ -46,45 +50,60 @@ class BinarySearchTree {
// 迴圈查詢,越過葉節點後跳出
while (cur != null) {
// 找到重複節點,直接返回
if (cur.value == num) return
if (cur._val == num)
return
pre = cur
// 插入位置在 cur 的右子樹中
cur = if (cur.value < num) cur.right
cur = if (cur._val < num)
cur.right
// 插入位置在 cur 的左子樹中
else cur.left
else
cur.left
}
// 插入節點
val node = TreeNode(num)
if (pre?.value!! < num) pre.right = node
else pre.left = node
if (pre?._val!! < num)
pre.right = node
else
pre.left = node
}
/* 刪除節點 */
fun remove(num: Int) {
// 若樹為空,直接提前返回
if (root == null) return
if (root == null)
return
var cur = root
var pre: TreeNode? = null
// 迴圈查詢,越過葉節點後跳出
while (cur != null) {
// 找到待刪除節點,跳出迴圈
if (cur.value == num) break
if (cur._val == num)
break
pre = cur
// 待刪除節點在 cur 的右子樹中
cur = if (cur.value < num) cur.right
cur = if (cur._val < num)
cur.right
// 待刪除節點在 cur 的左子樹中
else cur.left
else
cur.left
}
// 若無待刪除節點,則直接返回
if (cur == null) return
if (cur == null)
return
// 子節點數量 = 0 or 1
if (cur.left == null || cur.right == null) {
// 當子節點數量 = 0 / 1 時, child = null / 該子節點
val child = if (cur.left != null) cur.left else cur.right
val child = if (cur.left != null)
cur.left
else
cur.right
// 刪除節點 cur
if (cur != root) {
if (pre!!.left == cur) pre.left = child
else pre.right = child
if (pre!!.left == cur)
pre.left = child
else
pre.right = child
} else {
// 若刪除節點為根節點,則重新指定根節點
root = child
@@ -97,9 +116,9 @@ class BinarySearchTree {
tmp = tmp.left
}
// 遞迴刪除節點 tmp
remove(tmp.value)
remove(tmp._val)
// 用 tmp 覆蓋 cur
cur.value = tmp.value
cur._val = tmp._val
}
}
}
@@ -118,7 +137,7 @@ fun main() {
/* 查詢節點 */
val node = bst.search(7)
println("查詢到的節點物件為 $node,節點值 = ${node?.value}")
println("查詢到的節點物件為 $node,節點值 = ${node?._val}")
/* 插入節點 */
bst.insert(16)
@@ -16,13 +16,14 @@ fun levelOrder(root: TreeNode?): MutableList<Int> {
val queue = LinkedList<TreeNode?>()
queue.add(root)
// 初始化一個串列,用於儲存走訪序列
val list = ArrayList<Int>()
while (!queue.isEmpty()) {
val node = queue.poll() // 隊列出隊
list.add(node?.value!!) // 儲存節點值
if (node.left != null) queue.offer(node.left) // 左子節點入列
if (node.right != null) queue.offer(node.right) // 右子節點入列
val list = mutableListOf<Int>()
while (queue.isNotEmpty()) {
val node = queue.poll() // 隊列出隊
list.add(node?._val!!) // 儲存節點值
if (node.left != null)
queue.offer(node.left) // 左子節點入列
if (node.right != null)
queue.offer(node.right) // 右子節點入列
}
return list
}
@@ -10,13 +10,13 @@ import utils.TreeNode
import utils.printTree
// 初始化串列,用於儲存走訪序列
var list = ArrayList<Int>()
var list = mutableListOf<Int>()
/* 前序走訪 */
fun preOrder(root: TreeNode?) {
if (root == null) return
// 訪問優先順序:根節點 -> 左子樹 -> 右子樹
list.add(root.value)
list.add(root._val)
preOrder(root.left)
preOrder(root.right)
}
@@ -26,7 +26,7 @@ fun inOrder(root: TreeNode?) {
if (root == null) return
// 訪問優先順序:左子樹 -> 根節點 -> 右子樹
inOrder(root.left)
list.add(root.value)
list.add(root._val)
inOrder(root.right)
}
@@ -36,7 +36,7 @@ fun postOrder(root: TreeNode?) {
// 訪問優先順序:左子樹 -> 右子樹 -> 根節點
postOrder(root.left)
postOrder(root.right)
list.add(root.value)
list.add(root._val)
}
/* Driver Code */
+4 -4
View File
@@ -7,7 +7,7 @@
package utils
/* 鏈結串列節點 */
class ListNode(var value: Int) {
class ListNode(var _val: Int) {
var next: ListNode? = null
companion object {
@@ -15,11 +15,11 @@ class ListNode(var value: Int) {
fun arrToLinkedList(arr: IntArray): ListNode? {
val dum = ListNode(0)
var head = dum
for (value in arr) {
head.next = ListNode(value)
for (_val in arr) {
head.next = ListNode(_val)
head = head.next!!
}
return dum.next
}
}
}
}
+9 -8
View File
@@ -20,7 +20,7 @@ fun <T> printMatrix(matrix: Array<Array<T>>) {
}
/* 列印矩陣(List */
fun <T> printMatrix(matrix: List<List<T>>) {
fun <T> printMatrix(matrix: MutableList<MutableList<T>>) {
println("[")
for (row in matrix) {
println(" $row,")
@@ -31,9 +31,9 @@ fun <T> printMatrix(matrix: List<List<T>>) {
/* 列印鏈結串列 */
fun printLinkedList(h: ListNode?) {
var head = h
val list = ArrayList<String>()
val list = mutableListOf<String>()
while (head != null) {
list.add(head.value.toString())
list.add(head._val.toString())
head = head.next
}
println(list.joinToString(separator = " -> "))
@@ -70,7 +70,7 @@ fun printTree(root: TreeNode?, prev: Trunk?, isRight: Boolean) {
}
showTrunks(trunk)
println(" ${root.value}")
println(" ${root._val}")
if (prev != null) {
prev.str = prevStr
@@ -91,16 +91,17 @@ fun showTrunks(p: Trunk?) {
/* 列印雜湊表 */
fun <K, V> printHashMap(map: Map<K, V>) {
for ((key, value) in map) {
println(key.toString() + " -> " + value)
println("${key.toString()} -> $value")
}
}
/* 列印堆積 */
fun printHeap(queue: Queue<Int>?) {
val list = queue?.let { ArrayList(it) }
val list = mutableListOf<Int?>()
queue?.let { list.addAll(it) }
print("堆積的陣列表示:")
println(list)
println("堆積的樹狀表示:")
val root = list?.let { TreeNode.listToTree(it) }
val root = TreeNode.listToTree(list)
printTree(root)
}
}
+5 -4
View File
@@ -7,8 +7,9 @@
package utils
/* 二元樹節點類別 */
/* 建構子 */
class TreeNode(
var value: Int // 節點值
var _val: Int // 節點值
) {
var height: Int = 0 // 節點高度
var left: TreeNode? = null // 左子節點引用
@@ -53,14 +54,14 @@ class TreeNode(
while (i >= res.size) {
res.add(null)
}
res[i] = root.value
res[i] = root._val
treeToListDFS(root.left, 2 * i + 1, res)
treeToListDFS(root.right, 2 * i + 2, res)
}
/* 將二元樹序列化為串列 */
fun treeToList(root: TreeNode?): List<Int?> {
val res = ArrayList<Int?>()
fun treeToList(root: TreeNode?): MutableList<Int?> {
val res = mutableListOf<Int?>()
treeToListDFS(root, 0, res)
return res
}
+4 -4
View File
@@ -7,7 +7,7 @@
package utils
/* 頂點類別 */
class Vertex(val value: Int) {
class Vertex(val _val: Int) {
companion object {
/* 輸入值串列 vals ,返回頂點串列 vets */
fun valsToVets(vals: IntArray): Array<Vertex?> {
@@ -19,10 +19,10 @@ class Vertex(val value: Int) {
}
/* 輸入頂點串列 vets ,返回值串列 vals */
fun vetsToVals(vets: List<Vertex?>): List<Int> {
val vals = ArrayList<Int>()
fun vetsToVals(vets: MutableList<Vertex?>): MutableList<Int> {
val vals = mutableListOf<Int>()
for (vet in vets) {
vals.add(vet!!.value)
vals.add(vet!!._val)
}
return vals
}