Syncing Up
This commit is contained in:
72
go/binary-search-tree/README.md
Normal file
72
go/binary-search-tree/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Binary Search Tree
|
||||
|
||||
Write a program that inserts numbers and searches in a binary tree.
|
||||
|
||||
When we need to represent sorted data, an array does not make a good
|
||||
data structure.
|
||||
|
||||
Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes
|
||||
`[1, 3, 4, 5, 2]` now we must sort the entire array again! We can
|
||||
improve on this by realizing that we only need to make space for the new
|
||||
item `[1, nil, 3, 4, 5]`, and then adding the item in the space we
|
||||
added. But this still requires us to shift many elements down by one.
|
||||
|
||||
Binary Search Trees, however, can operate on sorted data much more
|
||||
efficiently.
|
||||
|
||||
A binary search tree consists of a series of connected nodes. Each node
|
||||
contains a piece of data (e.g. the number 3), a variable named `left`,
|
||||
and a variable named `right`. The `left` and `right` variables point at
|
||||
`nil`, or other nodes. Since these other nodes in turn have other nodes
|
||||
beneath them, we say that the left and right variables are pointing at
|
||||
subtrees. All data in the left subtree is less than or equal to the
|
||||
current node's data, and all data in the right subtree is greater than
|
||||
the current node's data.
|
||||
|
||||
For example, if we had a node containing the data 4, and we added the
|
||||
data 2, our tree would look like this:
|
||||
|
||||
4
|
||||
/
|
||||
2
|
||||
|
||||
If we then added 6, it would look like this:
|
||||
|
||||
4
|
||||
/ \
|
||||
2 6
|
||||
|
||||
If we then added 3, it would look like this
|
||||
|
||||
4
|
||||
/ \
|
||||
2 6
|
||||
\
|
||||
3
|
||||
|
||||
And if we then added 1, 5, and 7, it would look like this
|
||||
|
||||
4
|
||||
/ \
|
||||
/ \
|
||||
2 6
|
||||
/ \ / \
|
||||
1 3 5 7
|
||||
|
||||
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
|
||||
|
||||
Josh Cheek [https://twitter.com/josh_cheek](https://twitter.com/josh_cheek)
|
||||
|
||||
## Submitting Incomplete Problems
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
50
go/binary-search-tree/binary_search_tree.go
Normal file
50
go/binary-search-tree/binary_search_tree.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package binarysearchtree
|
||||
|
||||
// SearchTreeData is a Binary Search Tree node
|
||||
type SearchTreeData struct {
|
||||
data int
|
||||
left *SearchTreeData
|
||||
right *SearchTreeData
|
||||
}
|
||||
|
||||
// Bst creates a node from an int
|
||||
func Bst(n int) *SearchTreeData {
|
||||
return &SearchTreeData{data: n}
|
||||
}
|
||||
|
||||
// Insert finds the correct location for a new node and inserts it there.
|
||||
func (s *SearchTreeData) Insert(n int) *SearchTreeData {
|
||||
if s == nil {
|
||||
return Bst(n)
|
||||
}
|
||||
if s.data < n {
|
||||
s.right = s.right.Insert(n)
|
||||
} else {
|
||||
s.left = s.left.Insert(n)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// MapString maps a function to every node in the search tree and returns
|
||||
// the []string result of it.
|
||||
func (s *SearchTreeData) MapString(f func(int) string) []string {
|
||||
var ret []string
|
||||
if s != nil {
|
||||
ret = append(ret, s.left.MapString(f)...)
|
||||
ret = append(ret, f(s.data))
|
||||
ret = append(ret, s.right.MapString(f)...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// MapInt maps a function to every node in the search tree and returns
|
||||
// the []int result of it.
|
||||
func (s *SearchTreeData) MapInt(f func(int) int) []int {
|
||||
var ret []int
|
||||
if s != nil {
|
||||
ret = append(ret, s.left.MapInt(f)...)
|
||||
ret = append(ret, f(s.data))
|
||||
ret = append(ret, s.right.MapInt(f)...)
|
||||
}
|
||||
return ret
|
||||
}
|
199
go/binary-search-tree/binary_search_tree_test.go
Normal file
199
go/binary-search-tree/binary_search_tree_test.go
Normal file
@@ -0,0 +1,199 @@
|
||||
// API:
|
||||
//
|
||||
// type SearchTreeData struct {
|
||||
// left *SearchTreeData
|
||||
// data int
|
||||
// right *SearchTreeData
|
||||
// }
|
||||
//
|
||||
// func Bst(int) *SearchTreeData
|
||||
// func (*SearchTreeData) Insert(int)
|
||||
// func (*SearchTreeData) MapString(func(int) string) []string
|
||||
// func (*SearchTreeData) MapInt(func(int) int) []int
|
||||
|
||||
package binarysearchtree
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDataIsRetained(t *testing.T) {
|
||||
actual := Bst(4).data
|
||||
expected := 4
|
||||
if actual != expected {
|
||||
t.Errorf("Bst(4).data: %d, want %d.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertingLess(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(2)
|
||||
|
||||
actual := bst.data
|
||||
expected := 4
|
||||
if actual != expected {
|
||||
t.Errorf("bst.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.left.data
|
||||
expected = 2
|
||||
if actual != expected {
|
||||
t.Errorf("bst.left.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertingSame(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(4)
|
||||
|
||||
actual := bst.data
|
||||
expected := 4
|
||||
if actual != expected {
|
||||
t.Errorf("bst.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.left.data
|
||||
expected = 4
|
||||
if actual != expected {
|
||||
t.Errorf("bst.left.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertingMore(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(5)
|
||||
|
||||
actual := bst.data
|
||||
expected := 4
|
||||
if actual != expected {
|
||||
t.Errorf("bst.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.right.data
|
||||
expected = 5
|
||||
if actual != expected {
|
||||
t.Errorf("bst.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestComplexTree(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(2)
|
||||
bst.Insert(6)
|
||||
bst.Insert(1)
|
||||
bst.Insert(3)
|
||||
bst.Insert(7)
|
||||
bst.Insert(5)
|
||||
|
||||
actual := bst.data
|
||||
expected := 4
|
||||
if actual != expected {
|
||||
t.Errorf("bst.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.left.data
|
||||
expected = 2
|
||||
if actual != expected {
|
||||
t.Errorf("bst.left.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.left.left.data
|
||||
expected = 1
|
||||
if actual != expected {
|
||||
t.Errorf("bst.left.left.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.left.right.data
|
||||
expected = 3
|
||||
if actual != expected {
|
||||
t.Errorf("bst.left.right.data: %d, want %d.", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.right.data
|
||||
expected = 6
|
||||
if actual != expected {
|
||||
t.Errorf("bst.right.data: %d, want %d", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.right.left.data
|
||||
expected = 5
|
||||
if actual != expected {
|
||||
t.Errorf("bst.right.left.data: %d, want %d", actual, expected)
|
||||
}
|
||||
|
||||
actual = bst.right.right.data
|
||||
expected = 7
|
||||
if actual != expected {
|
||||
t.Errorf("bst.right.right.data: %d, want %d", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapStringWithOneElement(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
|
||||
actual := bst.MapString(strconv.Itoa)
|
||||
expected := []string{"4"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("bst.MapString(): %q, want %q.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapStringWithSmallElement(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(2)
|
||||
|
||||
actual := bst.MapString(strconv.Itoa)
|
||||
expected := []string{"2", "4"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("bst.MapString(): %q, want %q.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapStringWithLargeElement(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(5)
|
||||
|
||||
actual := bst.MapString(strconv.Itoa)
|
||||
expected := []string{"4", "5"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("bst.MapString(): %q, want %q.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapStringWithComplexStructure(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(2)
|
||||
bst.Insert(1)
|
||||
bst.Insert(3)
|
||||
bst.Insert(6)
|
||||
bst.Insert(7)
|
||||
bst.Insert(5)
|
||||
|
||||
actual := bst.MapString(strconv.Itoa)
|
||||
expected := []string{"1", "2", "3", "4", "5", "6", "7"}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("bst.MapString(): %q, want %q.", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapIntWithComplexStructure(t *testing.T) {
|
||||
bst := SearchTreeData{data: 4}
|
||||
bst.Insert(2)
|
||||
bst.Insert(1)
|
||||
bst.Insert(3)
|
||||
bst.Insert(6)
|
||||
bst.Insert(7)
|
||||
bst.Insert(5)
|
||||
|
||||
f := func(i int) int {
|
||||
return i
|
||||
}
|
||||
|
||||
actual := bst.MapInt(f)
|
||||
expected := []int{1, 2, 3, 4, 5, 6, 7}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("bst.MapString(): %v, want %v.", actual, expected)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user