但有一点要说明,In 函数的实现中有这样一段代码:
if sVal.Index(i).Interface() == needle {
...
}
Go 中并非任何类型都可以使用 == 比较的,如果元素中含有 slice 或 map,则可能会报错。
二分查找
以遍历确认元素是否存在有个缺点,那就是,如果数组或切片中包含了大量数据,比如 1000000 条数据,即一百万,最坏的情况是,我们要遍历 1000000 次才能确认,时间复杂度 On。
有什么办法可以降低遍历次数?
自然而然地想到的方法是二分查找,它的时间复杂度 log2(n) 。但这个算法有前提,需要依赖有序序列。
于是,第一个要我们解决的问题是使序列有序,Go 的标准库已经提供了这个功能,在 sort 包下。
示例代码如下:
fmt.Println(sort.SortInts([]int{4, 2, 5, 1, 6}))
对于 []int,我们使用的函数是 SortInts,如果是其他类型切片,sort 也提供了相关的函数,比如 []string 可通过 SortStrings 排序。
完成排序就可以进行二分查找,幸运的是,这个功能 Go 也提供了,[]int 类型对应函数是 SearchInts。
简单介绍下这个函数,先看定义:
func SearchInts(a []int, x int) int
输入参数容易理解,从切片 a 中搜索 x。重点要说下返回值,这对于我们后面确认元素是否存在至关重要。返回值的含义,返回查找元素在切片中的位置,如果元素不存在,则返回,在保持切片有序情况下,插入该元素应该在什么位置。
比如,序列如下:
1 2 6 8 9 11
假设,x 为 6,查找之后将发现它的位置在索引 2 处;x 如果是 7,发现不存在该元素,如果插入序列,将会放在 6 和 8 之间,索引位置是 3,因而返回值为 3。
代码测试下:
fmt.Println(sort.SearchInts([]int{1, 2, 6, 8, 9, 11}, 6)) // 2
fmt.Println(sort.SearchInts([]int{1, 2, 6, 8, 9, 11}, 7)) // 3
如果判断元素是否在序列中,只要判断返回位置上的值是否和查找的值相同即可。
但还有另外一种情况,如果插入元素位于序列最后,例如元素值为 12,插入位置即为序列的长度 6。如果直接查找 6 位置上的元素就可能发生越界的情况。那怎么办呢?其实判断返回是否大于切片长度即可,大于则说明元素不在切片序列中。
完整的实现代码如下:
func SortInIntSlice(haystack []int, needle int) bool {
sort.Ints(haystack)
index := sort.SearchInts(haystack, needle)
return index < len(haystack) && haystack[index] == needle
}
但这还有个问题,对于无序的场景,如果每次查询都要经过一次排序并不划算。最后能实现一次排序,稍微修改下代码。









