Syncing Up
This commit is contained in:
53
go/binary-search/README.md
Normal file
53
go/binary-search/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Binary Search
|
||||
|
||||
Write a program that implements a binary search algorithm.
|
||||
|
||||
Searching a sorted collection is a common task. A dictionary is a sorted
|
||||
list of word definitions. Given a word, one can find its definition. A
|
||||
telephone book is a sorted list of people's names, addresses, and
|
||||
telephone numbers. Knowing someone's name allows one to quickly find
|
||||
their telephone number and address.
|
||||
|
||||
If the list to be searched contains more than a few items (a dozen, say)
|
||||
a binary search will require far fewer comparisons than a linear search,
|
||||
but it imposes the requirement that the list be sorted.
|
||||
|
||||
In computer science, a binary search or half-interval search algorithm
|
||||
finds the position of a specified input value (the search "key") within
|
||||
an array sorted by key value.
|
||||
|
||||
In each step, the algorithm compares the search key value with the key
|
||||
value of the middle element of the array.
|
||||
|
||||
If the keys match, then a matching element has been found and its index,
|
||||
or position, is returned.
|
||||
|
||||
Otherwise, if the search key is less than the middle element's key, then
|
||||
the algorithm repeats its action on the sub-array to the left of the
|
||||
middle element or, if the search key is greater, on the sub-array to the
|
||||
right.
|
||||
|
||||
If the remaining array to be searched is empty, then the key cannot be
|
||||
found in the array and a special "not found" indication is returned.
|
||||
|
||||
A binary search halves the number of items to check with each iteration,
|
||||
so locating an item (or determining its absence) takes logarithmic time.
|
||||
A binary search is a dichotomic divide and conquer search algorithm.
|
||||
|
||||
To run the tests simply run the command `go test` in the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||
flag:
|
||||
|
||||
go test -bench .
|
||||
|
||||
For more detailed info about the Go track see the [help
|
||||
page](http://exercism.io/languages/go).
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [http://en.wikipedia.org/wiki/Binary_search_algorithm](http://en.wikipedia.org/wiki/Binary_search_algorithm)
|
||||
|
||||
## Submitting Incomplete Problems
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
58
go/binary-search/binary_search.go
Normal file
58
go/binary-search/binary_search.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package binarysearch
|
||||
|
||||
import "strconv"
|
||||
|
||||
// SearchInts searches a slice of ints for the first position that 'n' should
|
||||
// be inserted at and keep 'hay' sorted
|
||||
func SearchInts(hay []int, n int) int {
|
||||
if len(hay) == 0 || n < hay[0] {
|
||||
return 0
|
||||
}
|
||||
if n > hay[len(hay)-1] {
|
||||
return len(hay)
|
||||
}
|
||||
|
||||
mid := len(hay) / 2
|
||||
if hay[mid] < n {
|
||||
return mid + 1 + SearchInts(hay[mid+1:], n)
|
||||
}
|
||||
|
||||
if n < hay[mid] {
|
||||
return SearchInts(hay[:mid], n)
|
||||
}
|
||||
|
||||
for mid > 0 && hay[mid-1] == n {
|
||||
mid--
|
||||
}
|
||||
return mid
|
||||
}
|
||||
|
||||
// Message does the binary search and returns an english string representation
|
||||
// of the result
|
||||
func Message(hay []int, n int) string {
|
||||
if len(hay) == 0 {
|
||||
return "slice has no values"
|
||||
}
|
||||
v := SearchInts(hay, n)
|
||||
if v < len(hay) && hay[v] == n {
|
||||
switch v {
|
||||
case 0:
|
||||
return itoa(n) + " found at beginning of slice"
|
||||
case len(hay) - 1:
|
||||
return itoa(n) + " found at end of slice"
|
||||
}
|
||||
return itoa(n) + " found at index " + itoa(v)
|
||||
}
|
||||
switch v {
|
||||
case 0:
|
||||
return itoa(n) + " < all values"
|
||||
case len(hay):
|
||||
return itoa(n) + " > all " + itoa(len(hay)) + " values"
|
||||
}
|
||||
return itoa(n) + " > " + itoa(hay[v-1]) + " at index " + itoa(v-1) + ", < " + itoa(hay[v]) + " at index " + itoa(v)
|
||||
}
|
||||
|
||||
// itoa is because I'm tired of writing strconv.Itoa
|
||||
func itoa(v int) string {
|
||||
return strconv.Itoa(v)
|
||||
}
|
193
go/binary-search/binary_search_test.go
Normal file
193
go/binary-search/binary_search_test.go
Normal file
@@ -0,0 +1,193 @@
|
||||
// Go has binary search in the standard library. Let's reimplement
|
||||
// sort.SearchInts with the same API as documented in the standard library
|
||||
// at http://golang.org/pkg/sort/#Search. Note that there are some differences
|
||||
// with the exercise README.
|
||||
//
|
||||
// * If there are duplicate values of the key you are searching for, you can't
|
||||
// just stop at the first one you find; you must find the first occurance in
|
||||
// the slice.
|
||||
//
|
||||
// * There is no special "not found" indication. If the search key is not
|
||||
// present, SearchInts returns the index of the first value greater than the
|
||||
// search key. If the key is greater than all values in the slice, SearchInts
|
||||
// returns the length of the slice.
|
||||
//
|
||||
// * You can assume the slice is sorted in increasing order. There is no need
|
||||
// to check that it is sorted. (That would wreck the performance.)
|
||||
//
|
||||
// Try it on your own without peeking at the standard library code.
|
||||
|
||||
package binarysearch
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testData = []struct {
|
||||
ref string
|
||||
slice []int
|
||||
key int
|
||||
x int // expected result
|
||||
}{
|
||||
{"6 found at index 3",
|
||||
[]int{1, 3, 4, 6, 8, 9, 11},
|
||||
6, 3},
|
||||
{"9 found at index 5",
|
||||
[]int{1, 3, 4, 6, 8, 9, 11},
|
||||
9, 5},
|
||||
{"3 found at index 1",
|
||||
[]int{1, 3, 5, 8, 13, 21, 34, 55, 89, 144},
|
||||
3, 1},
|
||||
{"55 found at index 7",
|
||||
[]int{1, 3, 5, 8, 13, 21, 34, 55, 89, 144},
|
||||
55, 7},
|
||||
{"21 found at index 5",
|
||||
[]int{1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377},
|
||||
21, 5},
|
||||
{"34 found at index 6",
|
||||
[]int{1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377},
|
||||
34, 6},
|
||||
|
||||
{"1 found at beginning of slice",
|
||||
[]int{1, 3, 6},
|
||||
1, 0},
|
||||
{"6 found at end of slice",
|
||||
[]int{1, 3, 6},
|
||||
6, 2},
|
||||
{"2 > 1 at index 0, < 3 at index 1",
|
||||
[]int{1, 3, 6},
|
||||
2, 1},
|
||||
{"2 < all values",
|
||||
[]int{11, 13, 16},
|
||||
2, 0},
|
||||
{"21 > all 3 values",
|
||||
[]int{11, 13, 16},
|
||||
21, 3},
|
||||
{"1 found at beginning of slice",
|
||||
[]int{1, 1, 1, 1, 1, 3, 6}, // duplicates
|
||||
1, 0},
|
||||
{"3 found at index 1",
|
||||
[]int{1, 3, 3, 3, 3, 3, 6},
|
||||
3, 1},
|
||||
{"6 found at index 4",
|
||||
[]int{1, 3, 3, 3, 6, 6, 6},
|
||||
6, 4},
|
||||
{"-2 > -3 at index 1, < -1 at index 2",
|
||||
[]int{-6, -3, -1}, // negatives
|
||||
-2, 2},
|
||||
{"0 > -7 at index 4, < 1 at index 5",
|
||||
[]int{-19, -17, -15, -12, -7, 1, 14, 35, 69, 124},
|
||||
0, 5},
|
||||
{"slice has no values",
|
||||
nil, 0, 0},
|
||||
}
|
||||
|
||||
func TestSearchInts(t *testing.T) {
|
||||
for _, test := range testData {
|
||||
if !sort.IntsAreSorted(test.slice) {
|
||||
t.Skip("Invalid test data")
|
||||
}
|
||||
if x := SearchInts(test.slice, test.key); x != test.x {
|
||||
t.Fatalf("SearchInts(%v, %d) = %d, want %d",
|
||||
test.slice, test.key, x, test.x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did you get it? Did you cut and paste from the standard library?
|
||||
// Whatever. Now show you can work it.
|
||||
//
|
||||
// The test program will supply slices and keys and you will write a function
|
||||
// that searches and returns one of the following messages:
|
||||
//
|
||||
// k found at beginning of slice.
|
||||
// k found at end of slice.
|
||||
// k found at index fx.
|
||||
// k < all values.
|
||||
// k > all n values.
|
||||
// k > lv at lx, < gv at gx.
|
||||
// slice has no values.
|
||||
//
|
||||
// In your messages, substitute appropritate values for k, lv, and gv;
|
||||
// substitute indexes for fx, lx, and gx; substitute a number for n.
|
||||
//
|
||||
// In the function Message you will demonstrate a number of different ways
|
||||
// to test the result of SearchInts. Note that you would probably never need
|
||||
// all of these different tests in a real program. The point of the exercise
|
||||
// is just to show that it is possible to identify a number of different
|
||||
// conditions from the return value.
|
||||
func TestMessage(t *testing.T) {
|
||||
for _, test := range testData {
|
||||
if !sort.IntsAreSorted(test.slice) {
|
||||
t.Skip("Invalid test data")
|
||||
}
|
||||
if res := Message(test.slice, test.key); res != test.ref {
|
||||
t.Fatalf("Message(%v, %d) =\n%q\nwant:\n%q",
|
||||
test.slice, test.key, res, test.ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks also test searching larger random slices
|
||||
|
||||
func Benchmark1e2(b *testing.B) {
|
||||
s := make([]int, 1e2)
|
||||
for i := range s {
|
||||
s[i] = rand.Intn(len(s))
|
||||
}
|
||||
sort.Ints(s)
|
||||
k := rand.Intn(len(s))
|
||||
ref := sort.SearchInts(s, k)
|
||||
res := SearchInts(s, k)
|
||||
if ref != res {
|
||||
b.Fatalf(
|
||||
"Search of %d values gave different answer than sort.SearchInts",
|
||||
len(s))
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
SearchInts(s, k)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark1e4(b *testing.B) {
|
||||
s := make([]int, 1e4)
|
||||
for i := range s {
|
||||
s[i] = rand.Intn(len(s))
|
||||
}
|
||||
sort.Ints(s)
|
||||
k := rand.Intn(len(s))
|
||||
ref := sort.SearchInts(s, k)
|
||||
res := SearchInts(s, k)
|
||||
if ref != res {
|
||||
b.Fatalf(
|
||||
"Search of %d values gave different answer than sort.SearchInts",
|
||||
len(s))
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
SearchInts(s, k)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark1e6(b *testing.B) {
|
||||
s := make([]int, 1e6)
|
||||
for i := range s {
|
||||
s[i] = rand.Intn(len(s))
|
||||
}
|
||||
sort.Ints(s)
|
||||
k := rand.Intn(len(s))
|
||||
ref := sort.SearchInts(s, k)
|
||||
res := SearchInts(s, k)
|
||||
if ref != res {
|
||||
b.Fatalf(
|
||||
"Search of %d values gave different answer than sort.SearchInts",
|
||||
len(s))
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
SearchInts(s, k)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user