Commiting so jcbwlkr can take a look

This commit is contained in:
Brian Buller 2016-08-16 13:58:10 -05:00
parent ec4ec16ac2
commit 2a0c6f9e45
4 changed files with 222 additions and 117 deletions

Binary file not shown.

View File

@ -8,42 +8,22 @@ import (
func main() { func main() {
fmt.Println("Creating Set 1") fmt.Println("Creating Set 1")
s1 := stringset.NewFromSlice([]string{"a", "b"}) s1 := stringset.NewFromSlice([]string{"a"})
addAndOutput(s1, "A") addAndOutput(s1, "b")
addAndOutput(s1, "d")
s1.PrettyPrint()
return
addAndOutput(s1, "c") addAndOutput(s1, "c")
addAndOutput(s1, "B") addAndOutput(s1, "0")
addAndOutput(s1, "B1") addAndOutput(s1, "aa")
addAndOutput(s1, "A1") addAndOutput(s1, "aaa")
addAndOutput(s1, "B2")
addAndOutput(s1, "A2")
addAndOutput(s1, "B3")
addAndOutput(s1, "A3")
delAndOutput(s1, "a")
fmt.Println("Creating Set 2")
s2 := stringset.NewFromSlice([]string{"A", "c"})
addAndOutput(s2, "a")
addAndOutput(s2, "b")
addAndOutput(s2, "B1")
addAndOutput(s2, "A3")
addAndOutput(s2, "A2")
addAndOutput(s2, "B2")
addAndOutput(s2, "A1")
addAndOutput(s2, "B3")
addAndOutput(s2, "B")
s2.PrettyPrint()
delAndOutput(s2, "a")
s2.PrettyPrint()
} }
func addAndOutput(s *stringset.Set, val string) { func addAndOutput(s stringset.Set, val string) {
fmt.Println("Adding " + val) fmt.Println("Adding new value: " + val)
s.Add(val) s.Add(val)
fmt.Println(s.String())
} }
func delAndOutput(s *stringset.Set, val string) { func delAndOutput(s stringset.Set, val string) {
fmt.Println("Deleting " + val)
s.Delete(val) s.Delete(val)
fmt.Println(s.String())
} }

View File

@ -27,6 +27,7 @@ package stringset
// Format the empty set as {}. // Format the empty set as {}.
import ( import (
"fmt"
"math/rand" "math/rand"
"reflect" "reflect"
"strconv" "strconv"
@ -166,13 +167,17 @@ func TestEqual(t *testing.T) {
// helper for testing Add, Delete // helper for testing Add, Delete
func testEleOp(name string, op func(Set, string), cases []eleOpCase, t *testing.T) { func testEleOp(name string, op func(Set, string), cases []eleOpCase, t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
fmt.Print("Running Test Case: ")
fmt.Println(tc)
s := NewFromSlice(tc.set) s := NewFromSlice(tc.set)
op(s, tc.ele) op(s, tc.ele)
want := NewFromSlice(tc.want) want := NewFromSlice(tc.want)
if !Equal(s, want) { if !Equal(s, want) {
fmt.Println(s.String())
t.Fatalf("%v %s %q = %v, want %v", t.Fatalf("%v %s %q = %v, want %v",
NewFromSlice(tc.set), name, tc.ele, s, want) NewFromSlice(tc.set), name, tc.ele, s, want)
} }
fmt.Println("=== Done ===")
} }
} }

View File

@ -3,6 +3,7 @@ package stringset
import ( import (
"errors" "errors"
"fmt" "fmt"
"strconv"
"strings" "strings"
) )
@ -11,30 +12,30 @@ const testVersion = 3
// Set is a slice of strings that you can do set operations on. // Set is a slice of strings that you can do set operations on.
// I decided that I wanted to implement a binary tree for the storage // I decided that I wanted to implement a binary tree for the storage
type Set struct { type Set struct {
top SetValue top *Node
} }
type SetValue struct { type Node struct {
value string value string
left *SetValue left *Node
right *SetValue right *Node
} }
// New returns an empty Set // New returns an empty Set
func New() Set { func New() Set {
s := new(Set) s := new(Set)
s.top = SetValue{} s.top = &Node{}
return *s return *s
} }
// NewFromSlice takes a slice of strings and returns a Set // NewFromSlice takes a slice of strings and returns a Set
func NewFromSlice(s []string) Set { func NewFromSlice(s []string) Set {
ret := New() ret := New()
r := &ret
for i := range s { for i := range s {
ret.Add(s[i]) r.Add(s[i])
} }
ret.balance() return *r
return ret
} }
// Add adds a value to the set // Add adds a value to the set
@ -43,71 +44,32 @@ func (s Set) Add(v string) {
s.top.value = v s.top.value = v
return return
} }
s.top.Add(v) if !s.Has(v) {
} bef := "Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue()
newNode := s.top.Add(&Node{value: v})
fmt.Println(bef)
fmt.Println("Current New Node: " + newNode.value + ";L:" + newNode.getLeftValue() + ";R:" + newNode.getRightValue())
fmt.Printf("newNode.left: %v (%v)\n", &newNode.left, newNode.left)
s.top.value = newNode.value
s.top.left = newNode.left
s.top.right = newNode.right
fmt.Println("Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue())
fmt.Printf("s.top.left: %v (%v)\n", &s.top.left, s.top.left)
fmt.Println("Add Done")
func (s *Set) PrettyPrint() { //s.top = s.top.Add(newNode)
s.pp(&s.top, 0) //fmt.Println("Current Top Node: " + s.top.value + ";L:" + s.top.getLeftValue() + ";R:" + s.top.getRightValue())
}
func (s *Set) pp(n *SetValue, indent int) {
if n != nil {
if n.left != nil {
s.pp(n.left, indent+4)
}
if n.right != nil {
s.pp(n.right, indent+4)
}
for ; indent > 0; indent-- {
fmt.Print(" ")
}
fmt.Println(n.value)
} }
} }
// balance balances the binary tree
func (s *Set) balance() {
}
func (s *Set) find(v string) *SetValue {
if s.top.value != "" {
sv, _ := s.top.find(v)
return sv
}
return nil
}
// findWithParent finds a node with a child value v
// a return of nil, nil means it's the top node
func (s *Set) findParent(v string) (*SetValue, error) {
if s.top.value == v {
// no parent, it's the top.
return nil, nil
} else {
return s.top.findParent(v)
}
return nil, errors.New("Empty Set")
}
func (s *Set) findHome(v *SetValue) {
if s.top.value == "" {
s.top.value = v.value
s.top.left = v.left
s.top.right = v.right
return
}
s.top.findHome(v)
}
// Delete removes the given value from the set // Delete removes the given value from the set
func (s Set) Delete(v string) { func (s Set) Delete(v string) {
if sv, err := s.findParent(v); err == nil { if sv, err := s.findParent(v); err == nil {
var cmp int var cmp int
var delNode, repNode, orphan *SetValue var delNode, repNode, orphan *Node
if sv == nil { if sv == nil {
// Deleting 'top' // Deleting 'top'
delNode = &s.top delNode = s.top
if delNode.left != nil { if delNode.left != nil {
repNode = delNode.left repNode = delNode.left
orphan = delNode.right orphan = delNode.right
@ -118,15 +80,13 @@ func (s Set) Delete(v string) {
// No node to replace it with, we're done // No node to replace it with, we're done
return return
} }
s.top = *repNode s.top = repNode
} else { } else {
cmp = strings.Compare(v, sv.value) cmp = strings.Compare(v, sv.value)
if cmp < 0 && sv.left != nil { if cmp < 0 && sv.left != nil {
fmt.Println(" Left: " + sv.left.value)
// It's the left node // It's the left node
delNode = sv.left delNode = sv.left
} else if cmp > 0 && sv.right != nil { } else if cmp > 0 && sv.right != nil {
fmt.Println(" Right: " + sv.right.value)
// It's the right node // It's the right node
delNode = sv.right delNode = sv.right
} }
@ -157,6 +117,62 @@ func (s Set) Delete(v string) {
} }
} }
func (s Set) PrettyPrint() {
fmt.Println("=========")
s.pp(s.top, 0)
fmt.Println("=========")
}
func (s Set) pp(n *Node, indent int) {
if n.left == n || n.right == n {
// Circular reference...
fmt.Println("Circular reference... You done messed up.")
return
}
if n != nil {
if n.left != nil {
s.pp(n.left, indent+4)
}
if n.right != nil {
s.pp(n.right, indent+4)
}
for ; indent > 0; indent-- {
fmt.Print(" ")
}
fmt.Println(n.value)
}
}
func (s *Set) find(v string) *Node {
if s.top.value != "" {
sv, _ := s.top.find(v)
return sv
}
return nil
}
// findWithParent finds a node with a child value v
// a return of nil, nil means it's the top node
func (s *Set) findParent(v string) (*Node, error) {
if s.top.value == v {
// no parent, it's the top.
return nil, nil
} else {
return s.top.findParent(v)
}
return nil, errors.New("Empty Set")
}
func (s *Set) findHome(v *Node) {
if s.top.value == "" {
s.top.value = v.value
s.top.left = v.left
s.top.right = v.right
return
}
s.top.findHome(v)
}
// Has returns if the set contains the given value. // Has returns if the set contains the given value.
func (s *Set) Has(v string) bool { func (s *Set) Has(v string) bool {
return s.find(v) != nil return s.find(v) != nil
@ -195,7 +211,7 @@ func (s Set) String() string {
// find looks for a node with value val, it either returns the node // find looks for a node with value val, it either returns the node
// or an error stating it couldn't find it. // or an error stating it couldn't find it.
func (sv *SetValue) find(val string) (*SetValue, error) { func (sv *Node) find(val string) (*Node, error) {
if sv.value == val { if sv.value == val {
return sv, nil return sv, nil
} }
@ -211,7 +227,7 @@ func (sv *SetValue) find(val string) (*SetValue, error) {
// findParent looks for the parent of the node with value val // findParent looks for the parent of the node with value val
// If nil, nil is returned, it _is_ this node. // If nil, nil is returned, it _is_ this node.
func (sv *SetValue) findParent(val string) (*SetValue, error) { func (sv *Node) findParent(val string) (*Node, error) {
if sv.value == val { if sv.value == val {
// This should only trigger if this is the top node of the tree // This should only trigger if this is the top node of the tree
return nil, nil return nil, nil
@ -232,7 +248,7 @@ func (sv *SetValue) findParent(val string) (*SetValue, error) {
return nil, errors.New("Value not found") return nil, errors.New("Value not found")
} }
func (sv *SetValue) findHome(v *SetValue) { func (sv *Node) findHome(v *Node) {
cmp := strings.Compare(v.value, sv.value) cmp := strings.Compare(v.value, sv.value)
if cmp < 0 { if cmp < 0 {
if sv.left == nil { if sv.left == nil {
@ -257,25 +273,86 @@ func (sv *SetValue) findHome(v *SetValue) {
} }
} }
func (sv *SetValue) Add(v string) { func (sv *Node) Add(n *Node) *Node {
cmp := strings.Compare(v, sv.value) fmt.Println("1 Adding at Node " + sv.value)
cmp := strings.Compare(n.value, sv.value)
if cmp < 0 { if cmp < 0 {
fmt.Println("2 checking to left")
if sv.left == nil { if sv.left == nil {
sv.left = &SetValue{value: v} fmt.Println("3 left is nil, add it")
sv.left = n
} else { } else {
sv.left.Add(v) fmt.Println("--> 4 recurse left")
sv.left = sv.left.Add(n)
fmt.Println("<-- 5 added to left")
} }
} else if cmp > 0 { } else {
fmt.Println("6 checking to right")
if sv.right == nil { if sv.right == nil {
sv.right = &SetValue{value: v} fmt.Println("7 right is nil, add it")
sv.right = n
} else { } else {
sv.right.Add(v) fmt.Println("--> 8 recurse right")
sv.right = sv.right.Add(n)
fmt.Println("<-- 9 added to right")
} }
} }
fmt.Println("10 let's balance now (sv: " + sv.value + ")")
balance := GetBalance(sv)
// left left unbalance
fmt.Println("11 balance: " + strconv.Itoa(balance))
newVal := sv
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) < 0 { // < sv.left.value {
fmt.Println("12 Left Left")
newVal = RightRotate(sv)
fmt.Println("13")
}
// right right unbalance
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) > 0 { //n.value > sv.right.value {
fmt.Println("14 Right Right")
newVal = LeftRotate(sv)
fmt.Println("15")
}
// left right unbalance
if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) > 0 { //n.value > sv.left.value {
fmt.Println("16 Left Right")
sv.left = LeftRotate(sv.left)
fmt.Println("17")
newVal = RightRotate(sv)
fmt.Println("18")
}
// right left unbalance
if balance < -1 && strings.Compare(n.value, sv.getRightValue()) < 0 { //n.value < sv.right.value {
fmt.Println("19 Right Left")
sv.right = RightRotate(sv.right)
fmt.Println("20")
newVal = LeftRotate(sv)
fmt.Println("21")
}
fmt.Println("22 end add")
return newVal
}
func (sv *Node) getLeftValue() string {
if sv.left == nil {
return ""
}
return sv.left.value
}
func (sv *Node) getRightValue() string {
if sv.right == nil {
return ""
}
return sv.right.value
} }
// Len returns how many elements are in the branches // Len returns how many elements are in the branches
func (sv *SetValue) Len() int { func (sv *Node) Len() int {
if sv == nil {
return 0
}
ret := 1 ret := 1
if sv.left != nil { if sv.left != nil {
ret += sv.left.Len() ret += sv.left.Len()
@ -287,26 +364,34 @@ func (sv *SetValue) Len() int {
} }
// Has checks if this branch contains the value v // Has checks if this branch contains the value v
func (sv *SetValue) Has(v string) bool { func (sv *Node) Has(v string) bool {
ret, _ := sv.find(v) ret, _ := sv.find(v)
return ret != nil return ret != nil
} }
// String gets a string value of this branch // String gets a string value of this branch
func (sv *SetValue) String() string { func (sv *Node) String() string {
var ret string var ret string
if sv.left != nil { if sv.left != nil {
ret += sv.left.String() + ", " if sv.left == sv {
ret += "**, "
} else {
ret += sv.left.String() + ", "
}
} }
ret += "\"" + sv.value + "\"" ret += "\"" + sv.value + "\""
if sv.right != nil { if sv.right != nil {
ret += ", " + sv.right.String() if sv.right == sv {
ret += "**, "
} else {
ret += ", " + sv.right.String()
}
} }
return ret return ret
} }
// Slice returns a string slice of all values in the branch // Slice returns a string slice of all values in the branch
func (sv *SetValue) Slice() []string { func (sv *Node) Slice() []string {
var ret []string var ret []string
if sv.left != nil { if sv.left != nil {
ret = sv.left.Slice() ret = sv.left.Slice()
@ -325,9 +410,6 @@ func Equal(s1, s2 Set) bool {
// Subset returns whether s1 is a subset of s2. // Subset returns whether s1 is a subset of s2.
func Subset(s1, s2 Set) bool { func Subset(s1, s2 Set) bool {
if s1.Len() == 0 || s2.Len() == 0 {
return false
}
s1Sl := s1.Slice() s1Sl := s1.Slice()
for i := range s1Sl { for i := range s1Sl {
if !s2.Has(s1Sl[i]) { if !s2.Has(s1Sl[i]) {
@ -345,7 +427,7 @@ func Disjoint(s1, s2 Set) bool {
return false return false
} }
} }
return false return true
} }
// Intersection finds elements that exist in both sets and makes a new // Intersection finds elements that exist in both sets and makes a new
@ -386,3 +468,41 @@ func Difference(s1, s2 Set) Set {
func SymmetricDifference(s1, s2 Set) Set { func SymmetricDifference(s1, s2 Set) Set {
return Union(Difference(s1, s2), Difference(s2, s1)) return Union(Difference(s1, s2), Difference(s2, s1))
} }
/* Helper Functions for Balancing the Tree */
func RightRotate(y *Node) *Node {
x := y.left
t2 := x.right
// Perform rotation
x.right = y
y.left = t2
fmt.Println("RightRotate: return=" + x.value + "; L:" + x.left.value + "; R:" + x.right.value)
fmt.Println("RightRotate: leftNode=" + x.getLeftValue() + "; L:" + x.left.getLeftValue() + "; R:" + x.left.getRightValue())
fmt.Println("RightRotate: rightNode=" + x.getRightValue() + "; L:" + x.right.getLeftValue() + "; R:" + x.right.getRightValue())
// Return new root
return x
}
func LeftRotate(x *Node) *Node {
y := x.right
t2 := y.left
// Perform rotation
y.left = x
x.right = t2
// Return new root
fmt.Println("LeftRotate: return=" + y.value + "; L:" + y.left.value + "; R:" + y.right.value)
fmt.Println("LeftRotate: leftNode=" + y.getLeftValue() + "; L:" + y.left.getLeftValue() + "; R:" + y.left.getRightValue())
fmt.Println("LeftRotate: rightNode=" + y.getRightValue() + "; L:" + y.right.getLeftValue() + "; R:" + y.right.getRightValue())
return y
}
func GetBalance(n *Node) int {
if n == nil {
return 0
}
return n.left.Len() - n.right.Len()
}
func CompareNodes(n1, n2 *Node) int {
return strings.Compare(n1.value, n2.value)
}