Golang 中二分查找包的使用方法 Go 标准库中的 sort 包提供了二分查找的功能,主要通过 sort.Search 函数实现。下面详细介绍如何使用这个功能。
二分法通用模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 func  binarySearch (nums []int , target int )   int  {    left, right := 0 , len (nums)-1            for  left <= right {          mid := left + (right-left)/2                    if  nums[mid] == target {             return  mid          } else  if  nums[mid] < target {             left = mid + 1           } else  {             right = mid - 1           }     }          return  -1   } func  findLeftBound (nums []int , target int )   int  {    left, right := 0 , len (nums)-1      res := -1           for  left <= right {         mid := left + (right-left)/2          if  nums[mid] >= target {             right = mid - 1          } else  {             left = mid + 1          }                  if  nums[mid] == target {             res = mid         }     }          return  res } func  findRightBound (nums []int , target int )   int  {    left, right := 0 , len (nums)-1      res := -1           for  left <= right {         mid := left + (right-left)/2          if  nums[mid] <= target {             left = mid + 1          } else  {             right = mid - 1          }                  if  nums[mid] == target {             res = mid         }     }          return  res } 
1. sort.Search 基本用法 sort.Search 函数的签名如下:
1 func  Search (n int , f func (int )   bool ) int 
它会在 [0, n) 范围内查找满足 f(i) 为 true 的最小索引 i。如果不存在这样的索引,则返回 n。
基本示例:在有序切片中查找元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package  mainimport  (	"fmt"  	"sort"  ) func  main ()   {	nums := []int {1 , 3 , 5 , 7 , 9 } 	target := 5  	 	index := sort.Search(len (nums), func (i int )   bool  { 		return  nums[i] >= target 	}) 	if  index < len (nums) && nums[index] == target { 		fmt.Printf("找到 %d,索引为 %d\n" , target, index) 	} else  { 		fmt.Printf("未找到 %d\n" , target) 	} } 
2. 查找特定条件的元素 sort.Search 的强大之处在于可以查找满足任意条件的第一个元素。
示例:查找第一个大于等于目标值的元素 1 2 3 4 5 6 7 8 nums := []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } target := 5  index := sort.Search(len (nums), func (i int )   bool  {     return  nums[i] >= target }) fmt.Printf("第一个大于等于 %d 的元素是 %d,索引为 %d\n" , target, nums[index], index) 
示例:查找第一个满足条件的偶数 1 2 3 4 5 6 7 8 9 10 11 nums := []int {1 , 3 , 5 , 6 , 7 , 9 , 10 , 11 } index := sort.Search(len (nums), func (i int )   bool  {     return  nums[i]%2  == 0  }) if  index < len (nums) {    fmt.Printf("第一个偶数是 %d,索引为 %d\n" , nums[index], index) } else  {     fmt.Println("没有找到偶数" ) } 
3. 自定义类型的二分查找 对于自定义类型,需要先实现 sort.Interface 接口,然后才能使用 sort.Search。
示例:自定义结构体切片查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 type  Person struct  {    Name string      Age  int  } type  ByAge []Personfunc  (a ByAge)   Len() int            { return  len (a) }func  (a ByAge)   Swap(i, j int )      { a[i], a[j] = a[j], a[i] }func  (a ByAge)   Less(i, j int ) bool  { return  a[i].Age < a[j].Age }func  main ()   {    people := ByAge{         {"Alice" , 25 },         {"Bob" , 30 },         {"Charlie" , 35 },         {"Dave" , 40 },     }          sort.Sort(people)          targetAge := 33      index := sort.Search(len (people), func (i int )   bool  {         return  people[i].Age >= targetAge     })     if  index < len (people) {         fmt.Printf("找到 %+v,索引为 %d\n" , people[index], index)     } else  {         fmt.Println("没有找到满足条件的人" )     } } 
4. 查找浮点数近似值 sort.Search 也可以用于浮点数近似查找。
示例:查找平方根近似值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func  sqrt (x float64 )   float64  {         precision := 1e-6      low, high := 0.0 , x               for  high-low > precision {         mid := (low + high) / 2          if  mid*mid < x {             low = mid         } else  {             high = mid         }     }          return  (low + high) / 2  } func  main ()   {    fmt.Println("√2 ≈" , sqrt(2 )) } 
5. 查找切片中的插入位置 sort.Search 非常适合用来查找元素应该插入的位置。
示例:查找插入位置 1 2 3 4 5 6 7 8 9 nums := []int {1 , 3 , 5 , 7 , 9 } target := 6  index := sort.Search(len (nums), func (i int )   bool  {     return  nums[i] >= target }) fmt.Printf("%d 应该插入到索引 %d 的位置\n" , target, index) 
6. 标准库中的其他相关函数 除了 sort.Search,标准库还提供了:
sort.SearchInts(a []int, x int) int - 在已排序的 int 切片中查找 xsort.SearchFloat64s(a []float64, x float64) int - 在已排序的 float64 切片中查找 xsort.SearchStrings(a []string, x string) int - 在已排序的 string 切片中查找 x示例:使用 sort.SearchInts 1 2 3 4 5 6 7 8 9 10 nums := []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } target := 5  index := sort.SearchInts(nums, target) if  index < len (nums) && nums[index] == target {    fmt.Printf("找到 %d,索引为 %d\n" , target, index) } else  {     fmt.Printf("未找到 %d\n" , target) } 
7. 性能考虑 sort.Search 的时间复杂度是 O(log n),因为它使用的是二分查找算法。但需要注意:
切片必须是已排序的,否则结果不可靠 比较函数 f 应该尽可能简单高效 对于非常大的数据集,考虑内存局部性和缓存效应 8. 实际应用示例 示例:实现类似 C++ 的 lower_bound 和 upper_bound 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 func  lowerBound (nums []int , target int )   int  {    return  sort.Search(len (nums), func (i int )   bool  {         return  nums[i] >= target     }) } func  upperBound (nums []int , target int )   int  {    return  sort.Search(len (nums), func (i int )   bool  {         return  nums[i] > target     }) } func  main ()   {    nums := []int {1 , 2 , 2 , 2 , 3 , 4 , 5 }     target := 2           lb := lowerBound(nums, target)     ub := upperBound(nums, target)          fmt.Printf("lowerBound: %d, upperBound: %d\n" , lb, ub)     fmt.Printf("元素 %d 的出现次数: %d\n" , target, ub-lb) }