diff --git a/chapter_searching/binary_search_edge.md b/chapter_searching/binary_search_edge.md index 9f76b6428..431c092dc 100644 --- a/chapter_searching/binary_search_edge.md +++ b/chapter_searching/binary_search_edge.md @@ -105,8 +105,7 @@ comments: true ```python title="binary_search_edge.py" def binary_search_left_edge(nums: list[int], target: int) -> int: """二分查找最左一个元素""" - # 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - i, j = 0, len(nums) - 1 + i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1] while i <= j: m = (i + j) // 2 # 计算中点索引 m if nums[m] < target: @@ -123,7 +122,30 @@ comments: true === "Go" ```go title="binary_search_edge.go" - [class]{}-[func]{binarySearchLeftEdge} + /* 二分查找最左一个元素 */ + func binarySearchLeftEdge(nums []int, target int) int { + // 初始化双闭区间 [0, n-1] + i, j := 0, len(nums)-1 + for i <= j { + // 计算中点索引 m + m := i + (j-i)/2 + if nums[m] < target { + // target 在区间 [m+1, j] 中 + i = m + 1 + } else if nums[m] > target { + // target 在区间 [i, m-1] 中 + j = m - 1 + } else { + // 首个小于 target 的元素在区间 [i, m-1] 中 + j = m - 1 + } + } + if i == len(nums) || nums[i] != target { + // 未找到目标元素,返回 -1 + return -1 + } + return i + } ``` === "JavaScript" @@ -153,7 +175,26 @@ comments: true === "Swift" ```swift title="binary_search_edge.swift" - [class]{}-[func]{binarySearchLeftEdge} + /* 二分查找最左一个元素 */ + func binarySearchLeftEdge(nums: [Int], target: Int) -> Int { + // 初始化双闭区间 [0, n-1] + var i = 0 + var j = nums.count - 1 + while i <= j { + let m = i + (j - 1) / 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] 中 + } + } + if i == nums.count || nums[i] != target { + return -1 // 未找到目标元素,返回 -1 + } + return i + } ``` === "Zig" @@ -215,8 +256,7 @@ comments: true ```python title="binary_search_edge.py" def binary_search_right_edge(nums: list[int], target: int) -> int: """二分查找最右一个元素""" - # 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 - i, j = 0, len(nums) - 1 + i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1] while i <= j: m = (i + j) // 2 # 计算中点索引 m if nums[m] < target: @@ -233,7 +273,30 @@ comments: true === "Go" ```go title="binary_search_edge.go" - [class]{}-[func]{binarySearchRightEdge} + /* 二分查找最右一个元素 */ + func binarySearchRightEdge(nums []int, target int) int { + // 初始化双闭区间 [0, n-1] + i, j := 0, len(nums)-1 + for i <= j { + // 计算中点索引 m + m := i + (j-i)/2 + if nums[m] < target { + // target 在区间 [m+1, j] 中 + i = m + 1 + } else if nums[m] > target { + // target 在区间 [i, m-1] 中 + j = m - 1 + } else { + // 首个大于 target 的元素在区间 [m+1, j] 中 + i = m + 1 + } + } + if j < 0 || nums[j] != target { + // 未找到目标元素,返回 -1 + return -1 + } + return j + } ``` === "JavaScript" @@ -263,7 +326,26 @@ comments: true === "Swift" ```swift title="binary_search_edge.swift" - [class]{}-[func]{binarySearchRightEdge} + /* 二分查找最右一个元素 */ + func binarySearchRightEdge(nums: [Int], target: Int) -> Int { + // 初始化双闭区间 [0, n-1] + var i = 0 + var j = nums.count - 1 + while i <= j { + let 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 { + i = m + 1 // 首个大于 target 的元素在区间 [m+1, j] 中 + } + } + if j < 0 || nums[j] != target { + return -1 // 未找到目标元素,返回 -1 + } + return j + } ``` === "Zig" diff --git a/chapter_sorting/heap_sort.md b/chapter_sorting/heap_sort.md index e67bd4361..42da3ab78 100644 --- a/chapter_sorting/heap_sort.md +++ b/chapter_sorting/heap_sort.md @@ -187,9 +187,44 @@ comments: true === "Go" ```go title="heap_sort.go" - [class]{}-[func]{siftDown} + /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ + func siftDown(nums *[]int, n, i int) { + for true { + // 判断节点 i, l, r 中值最大的节点,记为 ma + l := 2*i + 1 + r := 2*i + 2 + ma := i + 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 + } + // 交换两节点 + (*nums)[i], (*nums)[ma] = (*nums)[ma], (*nums)[i] + // 循环向下堆化 + i = ma + } + } - [class]{}-[func]{heapSort} + /* 堆排序 */ + func heapSort(nums *[]int) { + // 建堆操作:堆化除叶节点以外的其他所有节点 + for i := len(*nums)/2 - 1; i >= 0; i-- { + siftDown(nums, len(*nums), i) + } + // 从堆中提取最大元素,循环 n-1 轮 + for i := len(*nums) - 1; i > 0; i-- { + // 交换根节点与最右叶节点(即交换首元素与尾元素) + (*nums)[0], (*nums)[i] = (*nums)[i], (*nums)[0] + // 以根节点为起点,从顶至底进行堆化 + siftDown(nums, i, 0) + } + } ``` === "JavaScript" @@ -227,9 +262,45 @@ comments: true === "Swift" ```swift title="heap_sort.swift" - [class]{}-[func]{siftDown} + /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */ + func siftDown(nums: inout [Int], n: Int, i: Int) { + var i = i + while true { + // 判断节点 i, l, r 中值最大的节点,记为 ma + let l = 2 * i + 1 + let 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 + } + // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出 + if ma == i { + break + } + // 交换两节点 + nums.swapAt(i, ma) + // 循环向下堆化 + i = ma + } + } - [class]{}-[func]{heapSort} + /* 堆排序 */ + func heapSort(nums: inout [Int]) { + // 建堆操作:堆化除叶节点以外的其他所有节点 + for i in stride(from: nums.count / 2 - 1, through: 0, by: -1) { + siftDown(nums: &nums, n: nums.count, i: i) + } + // 从堆中提取最大元素,循环 n-1 轮 + for i in stride(from: nums.count - 1, to: 0, by: -1) { + // 交换根节点与最右叶节点(即交换首元素与尾元素) + nums.swapAt(0, i) + // 以根节点为起点,从顶至底进行堆化 + siftDown(nums: &nums, n: i, i: 0) + } + } ``` === "Zig" diff --git a/chapter_sorting/selection_sort.md b/chapter_sorting/selection_sort.md index daf325fb0..80ee2a008 100644 --- a/chapter_sorting/selection_sort.md +++ b/chapter_sorting/selection_sort.md @@ -111,7 +111,24 @@ comments: true === "Go" ```go title="selection_sort.go" - [class]{}-[func]{selectionSort} + /* 选择排序 */ + func selectionSort(nums []int) { + n := len(nums) + // 外循环:未排序区间为 [i, n-1] + for i := 0; i < n-1; i++ { + // 内循环:找到未排序区间内的最小元素 + k := i + for j := i + 1; j < n; j++ { + if nums[j] < nums[k] { + // 记录最小元素的索引 + k = j + } + } + // 将该最小元素与未排序区间的首个元素交换 + nums[i], nums[k] = nums[k], nums[i] + + } + } ``` === "JavaScript" @@ -141,7 +158,21 @@ comments: true === "Swift" ```swift title="selection_sort.swift" - [class]{}-[func]{selectionSort} + /* 选择排序 */ + func selectionSort(nums: inout [Int]) { + // 外循环:未排序区间为 [i, n-1] + for i in nums.indices.dropLast() { + // 内循环:找到未排序区间内的最小元素 + var k = i + for j in nums.indices.dropFirst(i + 1) { + if nums[j] < nums[k] { + k = j // 记录最小元素的索引 + } + } + // 将该最小元素与未排序区间的首个元素交换 + nums.swapAt(i, k) + } + } ``` === "Zig"