Binary Search is a simple algorithm to find an item in an sorted array, and it’s usually referenced as a code sample to study when learning a new programming language.
Binary Search是一种简单的算法,可以在排序后的数组中查找项目,通常将其称为代码样本,以学习新的编程语言时进行研究。
功效 (Efficency)
It’s very efficient:
这非常有效:
Time: O(log n), it’s at worst logaritmic
时间: O(log n) ,对数最差
Space: 0(1), takes constant time
空间: 0(1) ,需要固定时间
理论 (Theory)
Given a sorted array, we pick the item Y in the middle and we compare it to the target value X.
给定一个排序数组,我们在中间选择项Y并将其与目标值X进行比较。
If Y matches X, we return the Y position and we exit.
如果Y与X匹配,则返回Y位置,然后退出。
We determine if X < Y, in this case we discard the right side, and we go in the middle of the left side, and we repeat the same operation as above.
我们确定是否X <Y,在这种情况下,我们丢弃右侧,然后移至左侧的中间,然后重复与上述相同的操作。
The search ends when Y finally matches X. If this does not happen, we return the position that X would have taken if it was in the array.
当Y最终与X匹配时,搜索结束。如果这没有发生,我们将返回X在数组中所处的位置。
实作 (Implementation)
We’re lucky, the Go standard library provides a binary tree implementation in its sort
package, in sort.Search()
.
幸运的是,Go标准库在sort
包中的sort.Search()
提供了一个二叉树实现。
Let’s see the usage of the API, as taken from the package documentation, so we know what sort.Search
should return:
让我们来看看API的用法,它来自软件包文档,因此我们知道什么样的sort.Search
应该返回:
package main
import (
"fmt"
"sort"
)
func main() {
a := []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55}
x := 6
i := sort.Search(len(a), func(i int) bool { return a[i] >= x })
if i < len(a) && a[i] == x {
fmt.Printf("found %d at index %d in %v\n", x, i, a)
} else {
fmt.Printf("%d not found in %v\n", x, a)
}
}
sort.Search
returns an index i
, and we just need to make sure that that index actually contains x
.
sort.Search
返回一个索引i
,我们只需要确保该索引实际包含x
。
Of course we want to know how this is implemented internally. Since the standard library is written in Go, and open source, it’s really easy to see how sort.Search
is implemented:
当然,我们想知道它是如何在内部实现的。 由于标准库是用Go语言和开源语言编写的,因此很容易看到sort.Search
是如何实现的:
func Search(n int, f func(int) bool) int {
// Define f(-1) == false and f(n) == true.
// Invariant: f(i-1) == false, f(j) == true.
i, j := 0, n
for i < j {
h := i + (j-i)/2 // avoid overflow when computing h
// i ≤ h < j
if !f(h) {
i = h + 1 // preserves f(i-1) == false
} else {
j = h // preserves f(j) == true
}
}
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
return i
}
Let’s break it down:
让我们分解一下:
Given an array with length n
, and a comparison function f
(that internally evaluates x >= a[h]
), we start iterating the array a
.
给定一个长度为n
的数组和一个比较函数f
(内部计算x >= a[h]
),我们开始迭代数组a
。
Let’s use the actual values we use in the example, it’s easier to show what’s happening.
让我们使用示例中使用的实际值,可以更轻松地显示正在发生的事情。
Data:
数据:
a := []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55}
x := 6
Iteration 1:
迭代1:
i
is0
,j
is9
.i
为0
,j
为9
。h
is calculated as(0 + (9-0) / 2)
=4
h
计算为(0 + (9-0) / 2)
=4
a[h]
is15
. This means we executej = h
a[h]
是15
。 这意味着我们执行j = h
Iteration 2:
迭代2:
i
is0
,j
is4
.i
为0
,j
为4
。h
is calculated as(0 + (4-0) / 2)
=2
h
计算为(0 + (4-0) / 2)
=2
a[h]
is6
. We found the position ofx
, this means we returnh = 2
a[h]
是6
。 我们找到了x
的位置,这意味着我们返回h = 2
搜索逆序 (Searching reverse order)
Since we can pass a function to sort.Search
, it’s easy to search on an array sorted in the reverse order, like
由于我们可以将函数传递给sort.Search
,因此很容易在以相反顺序排序的数组上进行搜索,例如
a := []int{55, 45, 36, 28, 21, 15, 10, 6, 3, 1}
x := 6
by passing a function that compares a[i] <= x
instead of a[i] >= x
.
通过传递比较a[i] <= x
而不是a[i] >= x
。
i := sort.Search(len(a), func(i int) bool { return a[i] <= x })
翻译自: https://flaviocopes.com/golang-algorithms-binary-search/