去二进制搜索错误

时间:2015-11-30 13:32:29

标签: search go binary-search

假设您有两个用例:

a := [] int {2, 2, 3, 4}
i := sort.Search(len(a), func(pos int) bool { return a[pos] == 2})
fmt.Printf("%v -> %v \n", a, i)

b := [] int {1, 2, 2, 3, 4}
j := sort.Search(len(b), func(pos int) bool { return b[pos] == 2})
fmt.Printf("%v -> %v \n", b, j)

答案是:

[2 2 3 4] -> 4
[1 2 2 3 4] -> 1

我想在两种情况下都必须是1,不是吗?有谁知道为什么?

1 个答案:

答案 0 :(得分:4)

sort.Search()返回i [0, n)f(i)的{​​{1}}中的最小索引true

由于切片索引从0开始,您应该期望第一个返回0,第二个返回1。它(貌似)适用于第二种。

从文档引用:

  

...假设在范围[0,n)上,f(i) == true暗示f(i+1) == true。也就是说,搜索要求ffalse表示输入范围[0,n]的某些(可能为空)前缀,然后true为(可能为空)余数;搜索返回第一个true索引。如果没有此类索引,搜索将返回n

您的功能不符合sort.Search()期望的标准。你的功能不是要判断指定索引处的元素是否是你要查找的元素,而是告诉:

  • 如果请求索引处的元素等于或大于(返回true
  • 或者指定索引处的元素小于搜索的元素(返回false)。

(如果您只知道它们何时相等,则无法执行二进制搜索,但是当它们更大或更小时则不能执行。)

因此,只需使用>=比较代替==。正确用法:

a := []int{2, 2, 3, 4}
i := sort.Search(len(a), func(pos int) bool { return a[pos] >= 2 })
fmt.Printf("%v -> %v \n", a, i)

b := []int{1, 2, 2, 3, 4}
j := sort.Search(len(b), func(pos int) bool { return b[pos] >= 2 })
fmt.Printf("%v -> %v \n", b, j)

输出(在 Go Playground 上试试):

[2 2 3 4] -> 0 
[1 2 2 3 4] -> 1 

注意:也来自doc:

  

例如,给定按升序排序的切片数据,调用

Search(len(data), func(i int) bool { return data[i] >= 23 })
     

返回最小的索引i,使data[i] >= 23。如果调用者想要查找切片中是否23,则必须单独测试data[i] == 23

更容易的替代方案:sort.SearchInts()

如果您想在int切片(int)中搜索[]int值,只需使用sort.SearchInts()

a := []int{2, 2, 3, 4}
i := sort.SearchInts(a, 2)
fmt.Printf("%v -> %v \n", a, i)

b := []int{1, 2, 2, 3, 4}
j := sort.SearchInts(b, 2)
fmt.Printf("%v -> %v \n", b, j)

输出(在 Go Playground 上试试):

[2 2 3 4] -> 0 
[1 2 2 3 4] -> 1