package stringset import ( "errors" "fmt" "strings" ) const testVersion = 3 // 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 type Set struct { top *Node } type Node struct { value string left *Node right *Node } // New returns an empty Set func New() Set { s := new(Set) s.top = &Node{} return *s } // NewFromSlice takes a slice of strings and returns a Set func NewFromSlice(s []string) Set { ret := New() r := &ret for i := range s { r.Add(s[i]) } return *r } // Add adds a value to the set func (s Set) Add(v string) { if s.top.value == "" { s.top.value = v return } if !s.Has(v) { newNode := s.top.Add(&Node{value: v}) s.top.value = newNode.value s.top.left = newNode.left s.top.right = newNode.right } } // Delete removes the given value from the set func (s Set) Delete(v string) { if sv, err := s.findParent(v); err == nil { var cmp int var delNode, repNode, orphan *Node if sv == nil { // Deleting 'top' delNode = s.top if delNode.left != nil { repNode = delNode.left orphan = delNode.right } else if delNode.right != nil { repNode = delNode.right } if repNode == nil { // No node to replace it with, we're done return } s.top = repNode } else { cmp = strings.Compare(v, sv.value) if cmp < 0 && sv.left != nil { // It's the left node delNode = sv.left } else if cmp > 0 && sv.right != nil { // It's the right node delNode = sv.right } if delNode == nil { return } if delNode.left != nil { repNode = delNode.left orphan = delNode.right } else if delNode.right != nil { repNode = delNode.right } if repNode == nil { // No replacement node, we're done return } if cmp < 0 { sv.left = repNode } else if cmp > 0 { sv.right = repNode } } // If we have an orphaned branch, find it a home if orphan != nil { s.findHome(orphan) } } } 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. func (s *Set) Has(v string) bool { return s.find(v) != nil } // IsEmpty returns whether the set is empty or not. func (s *Set) IsEmpty() bool { return s.top.value == "" } // Len returns the number of values in the set func (s *Set) Len() int { if !s.IsEmpty() { return s.top.Len() } return 0 } // Slice returns a string slice of the set func (s Set) Slice() []string { if !s.IsEmpty() { return s.top.Slice() } return []string{} } // String converts the set to a string func (s Set) String() string { ret := "{" if s.top.value != "" { ret += s.top.String() } ret += "}" return ret } // find looks for a node with value val, it either returns the node // or an error stating it couldn't find it. func (sv *Node) find(val string) (*Node, error) { if sv.value == val { return sv, nil } cmp := strings.Compare(val, sv.value) if cmp < 0 && sv.left != nil { return sv.left.find(val) } if cmp > 0 && sv.right != nil { return sv.right.find(val) } return nil, errors.New("Value not found") } // findParent looks for the parent of the node with value val // If nil, nil is returned, it _is_ this node. func (sv *Node) findParent(val string) (*Node, error) { if sv.value == val { // This should only trigger if this is the top node of the tree return nil, nil } cmp := strings.Compare(val, sv.value) if cmp < 0 && sv.left != nil { if sv.left.value == val { return sv, nil } return sv.left.findParent(val) } if cmp > 0 && sv.right != nil { if sv.right.value == val { return sv, nil } return sv.right.findParent(val) } return nil, errors.New("Value not found") } func (sv *Node) findHome(v *Node) { cmp := strings.Compare(v.value, sv.value) if cmp < 0 { if sv.left == nil { sv.left = v } else { sv.left.findHome(v) } } else if cmp > 0 { if sv.right == nil { sv.right = v } else { sv.right.findHome(v) } } else { // Discard the top node, find homes for it's children if v.left != nil { sv.findHome(v.left) } if v.right != nil { sv.findHome(v.right) } } } func (sv *Node) Add(n *Node) *Node { cmp := strings.Compare(n.value, sv.value) if cmp < 0 { if sv.left == nil { sv.left = n } else { sv.left = sv.left.Add(n) } } else { if sv.right == nil { sv.right = n } else { sv.right = sv.right.Add(n) } } newVal := sv /* TODO: Fix the tree balancing balance := GetBalance(sv) // left left unbalance if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) < 0 { newVal = RightRotate(sv) } // right right unbalance if balance < -1 && strings.Compare(n.value, sv.getRightValue()) > 0 { newVal = LeftRotate(sv) } // left right unbalance if balance > 1 && strings.Compare(n.value, sv.getLeftValue()) > 0 { sv.left = LeftRotate(sv.left) newVal = RightRotate(sv) } // right left unbalance if balance < -1 && strings.Compare(n.value, sv.getRightValue()) < 0 { sv.right = RightRotate(sv.right) newVal = LeftRotate(sv) } */ 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 func (sv *Node) Len() int { if sv == nil { return 0 } ret := 1 if sv.left != nil { ret += sv.left.Len() } if sv.right != nil { ret += sv.right.Len() } return ret } // Has checks if this branch contains the value v func (sv *Node) Has(v string) bool { ret, _ := sv.find(v) return ret != nil } // String gets a string value of this branch func (sv *Node) String() string { var ret string if sv.left != nil { if sv.left == sv { ret += "**, " } else { ret += sv.left.String() + ", " } } ret += "\"" + sv.value + "\"" if sv.right != nil { if sv.right == sv { ret += "**, " } else { ret += ", " + sv.right.String() } } return ret } // Slice returns a string slice of all values in the branch func (sv *Node) Slice() []string { var ret []string if sv.left != nil { ret = sv.left.Slice() } ret = append(ret, sv.value) if sv.right != nil { ret = append(ret, sv.right.Slice()...) } return ret } // Equal returns whether the given sets are the same. func Equal(s1, s2 Set) bool { return s1.String() == s2.String() } // Subset returns whether s1 is a subset of s2. func Subset(s1, s2 Set) bool { s1Sl := s1.Slice() for i := range s1Sl { if !s2.Has(s1Sl[i]) { return false } } return true } // Disjoint returns whether two sets _do not_ intersect func Disjoint(s1, s2 Set) bool { s1Sl := s1.Slice() for i := range s1Sl { if s2.Has(s1Sl[i]) { return false } } return true } // Intersection finds elements that exist in both sets and makes a new // set of them func Intersection(s1, s2 Set) Set { var vals []string s1Sl := s1.Slice() for i := range s1Sl { if s2.Has(s1Sl[i]) { vals = append(vals, s1Sl[i]) } } return NewFromSlice(vals) } // Union gets all elements in both sets and makes a new set with them. func Union(s1, s2 Set) Set { var vals []string vals = append(vals, s1.Slice()...) vals = append(vals, s2.Slice()...) return NewFromSlice(vals) } // Difference returns a Set of all elements in s1 that aren't in s2 func Difference(s1, s2 Set) Set { var vals []string s1Sl := s1.Slice() for i := range s1Sl { if !s2.Has(s1Sl[i]) { vals = append(vals, s1Sl[i]) } } return NewFromSlice(vals) } // SymmetricDifference returns all elements from s1 & s2 that occur in only one of the // sets. func SymmetricDifference(s1, s2 Set) Set { 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 // 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 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) }