Skip to content

Commit

Permalink
Merge pull request #904 from vaskoz/day348
Browse files Browse the repository at this point in the history
Day348
  • Loading branch information
vaskoz committed Feb 11, 2020
2 parents 168dd66 + 0ecfcdc commit 8e059fc
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ problems from
* [Day 345](https://github.com/vaskoz/dailycodingproblem-go/issues/687)
* [Day 346](https://github.com/vaskoz/dailycodingproblem-go/issues/688)
* [Day 347](https://github.com/vaskoz/dailycodingproblem-go/issues/689)
* [Day 348](https://github.com/vaskoz/dailycodingproblem-go/issues/693)
* [Day 350](https://github.com/vaskoz/dailycodingproblem-go/issues/695)
* [Day 352](https://github.com/vaskoz/dailycodingproblem-go/issues/699)
* [Day 353](https://github.com/vaskoz/dailycodingproblem-go/issues/701)
Expand Down
61 changes: 61 additions & 0 deletions day348/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package day348

// TernarySearchTree implements this tree:
// https://en.wikipedia.org/wiki/Ternary_search_tree
type TernarySearchTree struct {
letter rune
left, middle, right *TernarySearchTree
}

// Insert adds a word to the TernarySearchTree.
func (tst *TernarySearchTree) Insert(word string) {
if word == "" {
return
}

switch remaining, r := len(word), rune(word[0]); {
case tst.letter == 0 || tst.letter == r:
tst.letter = r
if remaining != 1 && tst.middle == nil {
tst.middle = &TernarySearchTree{}
}

tst = tst.middle
tst.Insert(word[1:])
case tst.letter > r:
if tst.left == nil {
tst.left = &TernarySearchTree{}
}

tst = tst.left
tst.Insert(word)
case tst.letter < r:
if tst.right == nil {
tst.right = &TernarySearchTree{}
}

tst = tst.right
tst.Insert(word)
}
}

// Search tries to find the word in the TernarySearchTree.
func (tst *TernarySearchTree) Search(word string) bool {
if word == "" {
return true
} else if tst == nil {
return false
}

switch r := rune(word[0]); {
case tst.letter == r:
tst = tst.middle
return tst.Search(word[1:])
case tst.letter > r:
tst = tst.left
return tst.Search(word)
default: // case tst.letter < r:
tst = tst.right
return tst.Search(word)
}
}
125 changes: 125 additions & 0 deletions day348/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package day348

import (
"testing"
)

// nolint
var testcases = []struct {
words []string
tree *TernarySearchTree
notWords []string
}{
{
[]string{"code", "cob", "be", "ax", "war", "we"},
&TernarySearchTree{
'c',
&TernarySearchTree{
'b',
&TernarySearchTree{
'a',
nil,
&TernarySearchTree{
'x', nil, nil, nil,
},
nil,
},
&TernarySearchTree{
'e', nil, nil, nil,
},
nil,
},
&TernarySearchTree{
'o',
nil,
&TernarySearchTree{
'd',
&TernarySearchTree{
'b',
nil,
nil,
nil,
},
&TernarySearchTree{
'e', nil, nil, nil,
},
nil,
},
nil,
},
&TernarySearchTree{
'w',
nil,
&TernarySearchTree{
'a',
nil,
&TernarySearchTree{
'r', nil, nil, nil,
},
&TernarySearchTree{
'e', nil, nil, nil,
},
},
nil,
},
},
[]string{"foo", "bar", "baz", "blahblahblah"},
},
}

func TestTernarySearchTree(t *testing.T) {
t.Parallel()

for _, tc := range testcases {
tree := &TernarySearchTree{}

for _, word := range tc.words {
tree.Insert(word)
}

if !equalTernaryTree(tree, tc.tree) {
t.Errorf("Expected trees to be equal but they aren't")
}

for _, word := range tc.words {
if !tree.Search(word) {
t.Errorf("Searching for word '%v' should return true", word)
}
}

for _, word := range tc.notWords {
if tree.Search(word) {
t.Errorf("Searching for notWord '%v' should return false", word)
}
}
}
}

func BenchmarkTernarySearchTree(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
tree := &TernarySearchTree{}

for _, word := range tc.words {
tree.Insert(word)
}

for _, word := range tc.words {
tree.Search(word)
}
}
}
}

func equalTernaryTree(a, b *TernarySearchTree) bool {
if a == nil && b == nil {
return true
} else if a != nil && b != nil {
return a.letter == b.letter &&
equalTernaryTree(a.left, b.left) &&
equalTernaryTree(a.middle, b.middle) &&
equalTernaryTree(a.right, b.right)
}

return false
}

0 comments on commit 8e059fc

Please sign in to comment.