项目中使用到有序数组查找特定元素,简单记录下Golang
中二分查找算法。
二分查找算法是一种在有序数组中查找特定元素的高效算法。它的基本思想是通过不断将查找范围缩小一半,来快速定位目标元素是否存在。该算法要求数组是有序的,这是因为有序数组的特性允许我们在每一步中排除掉一半的元素。
以下是二分查找的基本步骤:
初始化: 确定数组的初始搜索范围,通常是整个数组。设定low
和high
分别为搜索范围的最低和最高索引。
中间元素: 计算中间元素的索引,即mid = (low + high) / 2
。
比较: 将目标值与中间元素进行比较。
high = mid - 1
。low = mid + 1
。循环: 重复上述步骤,直到搜索范围缩小到无法再分割,即low > high
。此时,如果目标值存在,返回其索引;否则,返回-1表示目标值不存在。
二分查找的时间复杂度是O(log n),其中n是数组的大小。由于每一步都能将搜索范围减半,因此它在大型有序数组中的性能非常高效。这使得二分查找成为一种常用的查找算法。
请注意,二分查找要求数组是有序的,因此在使用之前需要确保数组有序。
package main
import "fmt"
// 二分查找函数
func binarySearch(arr []int, target int) int {
low, high := 0, len(arr)-1
for low <= high {
mid := (low + high) / 2
if arr[mid] == target {
return mid // 找到目标值,返回索引
} else if arr[mid] < target {
low = mid + 1 // 目标值在右半部分,缩小搜索范围
} else {
high = mid - 1 // 目标值在左半部分,缩小搜索范围
}
}
return -1 // 目标值不存在
}
func main() {
// 示例数组,必须是已排序的数组
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 要查找的目标值
target := 7
// 调用二分查找算法
index := binarySearch(arr, target)
if index != -1 {
fmt.Printf("目标值 %d 在数组中的索引是 %d\n", target, index)
} else {
fmt.Printf("目标值 %d 不存在于数组中\n", target)
}
}
在这个例子中,binarySearch
函数接受一个已排序的数组和目标值作为参数,然后使用二分查找算法找到目标值的索引。如果找到目标值,返回其索引;如果找不到,返回-1。在main
函数中,我们提供了一个已排序的数组和要查找的目标值,然后调用binarySearch
函数进行查找。
二分查找算法在进阶使用时,可以通过一些变体或特殊情况的处理来满足更复杂的需求。以下是一些二分查找算法的进阶使用场景和技巧:
在有序数组中,如果存在重复元素,可以通过稍作修改,使二分查找找到第一个等于目标值或最后一个等于目标值的元素。例如,找到数组中第一个等于目标值的索引:
func firstOccurrence(arr []int, target int) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := (low + high) / 2
if arr[mid] == target {
result = mid // 记录当前找到的索引
high = mid - 1 // 继续在左半部分查找
} else if arr[mid] < target {
low = mid + 1 // 目标值在右半部分,缩小搜索范围
} else {
high = mid - 1 // 目标值在左半部分,缩小搜索范围
}
}
return result
}
如果需要找到数组中第一个大于或等于目标值的元素,可以进行相应的调整:
func firstGreaterOrEqual(arr []int, target int) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := (low + high) / 2
if arr[mid] >= target {
result = mid // 记录当前找到的索引
high = mid - 1 // 继续在左半部分查找
} else {
low = mid + 1 // 目标值在右半部分,缩小搜索范围
}
}
return result
}
类似地,如果需要找到数组中最后一个小于或等于目标值的元素:
func lastLessOrEqual(arr []int, target int) int {
low, high := 0, len(arr)-1
result := -1
for low <= high {
mid := (low + high) / 2
if arr[mid] <= target {
result = mid // 记录当前找到的索引
low = mid + 1 // 继续在右半部分查找
} else {
high = mid - 1 // 目标值在左半部分,缩小搜索范围
}
}
return result
}
如果数组是循环有序的,可以先找到旋转点,然后分别在两个有序部分中进行二分查找。
这些进阶使用场景展示了如何通过适当的调整,使得二分查找算法适用于更多的情况。在实际应用中,根据具体问题的要求,可以进一步定制二分查找算法的逻辑。