blob: 8a2c1c33b14b36013925f74e6e560aca2d1b3c21 [file] [log] [blame]
Robert Griesemer194dde22010-11-10 13:19:28 -08001// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file implements binary search.
6
7package sort
8
Russ Cox19f0e462010-11-18 07:16:09 -05009// Search uses binary search to find and return the smallest index i
Robert Griesemer465b9c32012-10-30 13:38:01 -070010// in [0, n) at which f(i) is true, assuming that on the range [0, n),
Russ Cox285298b2010-11-18 11:46:07 -050011// f(i) == true implies f(i+1) == true. That is, Search requires that
12// f is false for some (possibly empty) prefix of the input range [0, n)
13// and then true for the (possibly empty) remainder; Search returns
14// the first true index. If there is no such index, Search returns n.
Shenghou Ma882eb602012-11-07 05:07:46 +080015// (Note that the "not found" return value is not -1 as in, for instance,
16// strings.Index).
Russ Cox19f0e462010-11-18 07:16:09 -050017// Search calls f(i) only for i in the range [0, n).
Robert Griesemer194dde22010-11-10 13:19:28 -080018//
Russ Cox19f0e462010-11-18 07:16:09 -050019// A common use of Search is to find the index i for a value x in
Rob Pike2b08e952011-06-16 17:48:02 +100020// a sorted, indexable data structure such as an array or slice.
Russ Cox19f0e462010-11-18 07:16:09 -050021// In this case, the argument f, typically a closure, captures the value
22// to be searched for, and how the data structure is indexed and
23// ordered.
Robert Griesemer194dde22010-11-10 13:19:28 -080024//
Russ Cox19f0e462010-11-18 07:16:09 -050025// For instance, given a slice data sorted in ascending order,
Russ Cox285298b2010-11-18 11:46:07 -050026// the call Search(len(data), func(i int) bool { return data[i] >= 23 })
Russ Cox19f0e462010-11-18 07:16:09 -050027// returns the smallest index i such that data[i] >= 23. If the caller
28// wants to find whether 23 is in the slice, it must test data[i] == 23
29// separately.
Robert Griesemer194dde22010-11-10 13:19:28 -080030//
Russ Cox285298b2010-11-18 11:46:07 -050031// Searching data sorted in descending order would use the <=
32// operator instead of the >= operator.
Robert Griesemer194dde22010-11-10 13:19:28 -080033//
Russ Cox19f0e462010-11-18 07:16:09 -050034// To complete the example above, the following code tries to find the value
35// x in an integer slice data sorted in ascending order:
Robert Griesemer194dde22010-11-10 13:19:28 -080036//
Russ Cox19f0e462010-11-18 07:16:09 -050037// x := 23
Russ Cox285298b2010-11-18 11:46:07 -050038// i := sort.Search(len(data), func(i int) bool { return data[i] >= x })
Russ Cox19f0e462010-11-18 07:16:09 -050039// if i < len(data) && data[i] == x {
40// // x is present at data[i]
Robert Griesemer194dde22010-11-10 13:19:28 -080041// } else {
Russ Cox19f0e462010-11-18 07:16:09 -050042// // x is not present in data,
43// // but i is the index where it would be inserted.
44// }
45//
46// As a more whimsical example, this program guesses your number:
47//
48// func GuessingGame() {
49// var s string
50// fmt.Printf("Pick an integer from 0 to 100.\n")
51// answer := sort.Search(100, func(i int) bool {
Russ Cox285298b2010-11-18 11:46:07 -050052// fmt.Printf("Is your number <= %d? ", i)
Russ Cox19f0e462010-11-18 07:16:09 -050053// fmt.Scanf("%s", &s)
54// return s != "" && s[0] == 'y'
55// })
56// fmt.Printf("Your number is %d.\n", answer)
Robert Griesemer194dde22010-11-10 13:19:28 -080057// }
Robert Griesemer8f651ff2010-11-12 16:08:56 -080058//
Robert Griesemer194dde22010-11-10 13:19:28 -080059func Search(n int, f func(int) bool) int {
Russ Cox285298b2010-11-18 11:46:07 -050060 // Define f(-1) == false and f(n) == true.
61 // Invariant: f(i-1) == false, f(j) == true.
Robert Griesemer194dde22010-11-10 13:19:28 -080062 i, j := 0, n
Russ Cox19f0e462010-11-18 07:16:09 -050063 for i < j {
Robert Griesemer194dde22010-11-10 13:19:28 -080064 h := i + (j-i)/2 // avoid overflow when computing h
Russ Cox19f0e462010-11-18 07:16:09 -050065 // i ≤ h < j
Russ Cox285298b2010-11-18 11:46:07 -050066 if !f(h) {
67 i = h + 1 // preserves f(i-1) == false
Robert Griesemer194dde22010-11-10 13:19:28 -080068 } else {
Russ Cox285298b2010-11-18 11:46:07 -050069 j = h // preserves f(j) == true
Robert Griesemer194dde22010-11-10 13:19:28 -080070 }
71 }
Russ Cox285298b2010-11-18 11:46:07 -050072 // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
Robert Griesemer194dde22010-11-10 13:19:28 -080073 return i
74}
75
Robert Griesemer194dde22010-11-10 13:19:28 -080076// Convenience wrappers for common cases.
77
Russ Coxf2b5a072011-01-19 23:09:00 -050078// SearchInts searches for x in a sorted slice of ints and returns the index
Shenghou Ma882eb602012-11-07 05:07:46 +080079// as specified by Search. The return value is the index to insert x if x is
80// not present (it could be len(a)).
Rob Pike20548b12012-11-02 16:17:34 -070081// The slice must be sorted in ascending order.
Robert Griesemer194dde22010-11-10 13:19:28 -080082//
83func SearchInts(a []int, x int) int {
Russ Cox285298b2010-11-18 11:46:07 -050084 return Search(len(a), func(i int) bool { return a[i] >= x })
Robert Griesemer194dde22010-11-10 13:19:28 -080085}
86
Russ Coxf2b5a072011-01-19 23:09:00 -050087// SearchFloat64s searches for x in a sorted slice of float64s and returns the index
Shenghou Ma882eb602012-11-07 05:07:46 +080088// as specified by Search. The return value is the index to insert x if x is not
89// present (it could be len(a)).
Rob Pike20548b12012-11-02 16:17:34 -070090// The slice must be sorted in ascending order.
Robert Griesemer465b9c32012-10-30 13:38:01 -070091//
Russ Coxf2b5a072011-01-19 23:09:00 -050092func SearchFloat64s(a []float64, x float64) int {
Russ Cox285298b2010-11-18 11:46:07 -050093 return Search(len(a), func(i int) bool { return a[i] >= x })
Robert Griesemer194dde22010-11-10 13:19:28 -080094}
95
Patrick Smith3c808162012-10-28 10:07:59 +110096// SearchStrings searches for x in a sorted slice of strings and returns the index
Shenghou Ma882eb602012-11-07 05:07:46 +080097// as specified by Search. The return value is the index to insert x if x is not
98// present (it could be len(a)).
Rob Pike20548b12012-11-02 16:17:34 -070099// The slice must be sorted in ascending order.
Robert Griesemer465b9c32012-10-30 13:38:01 -0700100//
Robert Griesemer194dde22010-11-10 13:19:28 -0800101func SearchStrings(a []string, x string) int {
Russ Cox285298b2010-11-18 11:46:07 -0500102 return Search(len(a), func(i int) bool { return a[i] >= x })
Robert Griesemer194dde22010-11-10 13:19:28 -0800103}
104
Robert Griesemer194dde22010-11-10 13:19:28 -0800105// Search returns the result of applying SearchInts to the receiver and x.
Rob Pike4b1170d2011-06-11 09:25:18 +1000106func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
Robert Griesemer194dde22010-11-10 13:19:28 -0800107
Russ Coxf2b5a072011-01-19 23:09:00 -0500108// Search returns the result of applying SearchFloat64s to the receiver and x.
Rob Pike2b08e952011-06-16 17:48:02 +1000109func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }
Robert Griesemer194dde22010-11-10 13:19:28 -0800110
Robert Griesemer194dde22010-11-10 13:19:28 -0800111// Search returns the result of applying SearchStrings to the receiver and x.
Rob Pike4b1170d2011-06-11 09:25:18 +1000112func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }