diff --git a/llrb/iterator.go b/llrb/iterator.go index 7504eab..241c16a 100644 --- a/llrb/iterator.go +++ b/llrb/iterator.go @@ -12,7 +12,7 @@ func (t *Tree) ascendGreaterOrEqual(h *Node, pivot Item, iterator ItemIterator) if h == nil { return true } - if !t.less(h.Item, pivot) { + if !h.Item.Less(pivot) { if !t.ascendGreaterOrEqual(h.Left, pivot, iterator) { return false } @@ -33,7 +33,7 @@ func (t *Tree) descendLessOrEqual(h *Node, pivot Item, iterator ItemIterator) bo if h == nil { return true } - if t.less(h.Item, pivot) || !t.less(pivot, h.Item) { + if h.Item.Less(pivot) || !pivot.Less(h.Item) { if !t.descendLessOrEqual(h.Right, pivot, iterator) { return false } diff --git a/llrb/iterator_deprecated.go b/llrb/iterator_deprecated.go deleted file mode 100644 index 92cbb93..0000000 --- a/llrb/iterator_deprecated.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2010 Petar Maymounkov. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -package llrb - -// IterAscend returns a chan that iterates through all elements in -// in ascending order. -// TODO: This is a deprecated interface for iteration. -func (t *Tree) IterAscend() <-chan Item { - c := make(chan Item) - go func() { - iterateInOrder(t.root, c) - close(c) - }() - return c -} - -// IterDescend returns a chan that iterates through all elements -// in descending order. -// TODO: This is a deprecated interface for iteration. -func (t *Tree) IterDescend() <-chan Item { - c := make(chan Item) - go func() { - iterateInOrderRev(t.root, c) - close(c) - }() - return c -} - -// IterRangeInclusive returns a chan that iterates through all elements E in the -// tree with lower <= E <= upper in ascending order. -// TODO: This is a deprecated interface for iteration. -func (t *Tree) IterRangeInclusive(lower, upper Item) <-chan Item { - c := make(chan Item) - go func() { - t.iterateRangeInclusive(t.root, c, lower, upper) - close(c) - }() - return c -} - -func (t *Tree) iterateRangeInclusive(h *Node, c chan<- Item, lower, upper Item) { - if h == nil { - return - } - lessThanLower := t.less(h.Item, lower) - greaterThanUpper := t.less(upper, h.Item) - if !lessThanLower { - t.iterateRangeInclusive(h.Left, c, lower, upper) - } - if !lessThanLower && !greaterThanUpper { - c <- h.Item - } - if !greaterThanUpper { - t.iterateRangeInclusive(h.Right, c, lower, upper) - } -} - -// IterRange() returns a chan that iterates through all elements E in the -// tree with lower <= E < upper in ascending order. -// TODO: This is a deprecated interface for iteration. -func (t *Tree) IterRange(lower, upper Item) <-chan Item { - c := make(chan Item) - go func() { - t.iterateRange(t.root, c, lower, upper) - close(c) - }() - return c -} - -func (t *Tree) iterateRange(h *Node, c chan<- Item, lower, upper Item) { - if h == nil { - return - } - lessThanLower := t.less(h.Item, lower) - lessThanUpper := t.less(h.Item, upper) - if !lessThanLower { - t.iterateRange(h.Left, c, lower, upper) - } - if !lessThanLower && lessThanUpper { - c <- h.Item - } - if lessThanUpper { - t.iterateRange(h.Right, c, lower, upper) - } -} - -func iterateInOrder(h *Node, c chan<- Item) { - if h == nil { - return - } - iterateInOrder(h.Left, c) - c <- h.Item - iterateInOrder(h.Right, c) -} - -func iterateInOrderRev(h *Node, c chan<- Item) { - if h == nil { - return - } - iterateInOrderRev(h.Right, c) - c <- h.Item - iterateInOrderRev(h.Left, c) -} - -func iteratePreOrder(h *Node, c chan<- Item) { - if h == nil { - return - } - c <- h.Item - iteratePreOrder(h.Left, c) - iteratePreOrder(h.Right, c) -} - -func iteratePostOrder(h *Node, c chan<- Item) { - if h == nil { - return - } - iteratePostOrder(h.Left, c) - iteratePostOrder(h.Right, c) - c <- h.Item -} diff --git a/llrb/llrb-stats.go b/llrb/llrb-stats.go index ada2f8b..1951914 100644 --- a/llrb/llrb-stats.go +++ b/llrb/llrb-stats.go @@ -13,11 +13,11 @@ func (t *Tree) getHeight(h *Node, item Item) (Item, int) { if h == nil { return nil, 0 } - if t.less(item, h.Item) { + if item.Less(h.Item) { result, depth := t.getHeight(h.Left, item) return result, depth + 1 } - if t.less(h.Item, item) { + if h.Item.Less(item) { result, depth := t.getHeight(h.Right, item) return result, depth + 1 } diff --git a/llrb/llrb.go b/llrb/llrb.go index 37ccbe8..dd43e45 100644 --- a/llrb/llrb.go +++ b/llrb/llrb.go @@ -2,11 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// A Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary search trees - -package llrb - -// Tree is a Left-Leaning Red-Black (LLRB) implementation of 2-3 trees, based on: +// A Left-Leaning Red-Black (LLRB) implementation of 2-3 balanced binary search trees, +// based on the following work: // // http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf // http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf @@ -17,8 +14,10 @@ package llrb // implementation of 2-3 trees is a recent improvement on the traditional implementation, // observed and documented by Robert Sedgewick. // +package llrb + +// Tree is a Left-Leaning Red-Black (LLRB) implementation of 2-3 trees type Tree struct { - less LessFunc count int root *Node } @@ -30,22 +29,13 @@ type Node struct { // In the LLRB, new nodes are always red, hence the zero-value for node } -type Item interface{} - -type LessFunc func(a, b interface{}) bool - -// New() allocates a new tree -func New(lessfunc LessFunc) *Tree { - t := &Tree{} - t.Init(lessfunc) - return t +type Item interface { + Less(than Item) bool } -// Init resets (empties) the tree -func (t *Tree) Init(lessfunc LessFunc) { - t.less = lessfunc - t.root = nil - t.count = 0 +// New() allocates a new tree +func New() *Tree { + return &Tree{} } // SetRoot sets the root node of the tree. @@ -63,21 +53,19 @@ func (t *Tree) Root() *Node { // Len returns the number of nodes in the tree. func (t *Tree) Len() int { return t.count } -// Has returns true if the tree contains an element -// whose LessThan order equals that of key. +// Has returns true if the tree contains an element whose order is the same as that of key. func (t *Tree) Has(key Item) bool { return t.Get(key) != nil } -// Get retrieves an element from the tree whose LessThan order -// equals that of key. +// Get retrieves an element from the tree whose order is the same as that of key. func (t *Tree) Get(key Item) Item { h := t.root for h != nil { switch { - case t.less(key, h.Item): + case key.Less(h.Item): h = h.Left - case t.less(h.Item, key): + case h.Item.Less(key): h = h.Right default: return h.Item @@ -145,9 +133,9 @@ func (t *Tree) replaceOrInsert(h *Node, item Item) (*Node, Item) { h = walkDownRot23(h) var replaced Item - if t.less(item, h.Item) { // BUG + if item.Less(h.Item) { // BUG h.Left, replaced = t.replaceOrInsert(h.Left, item) - } else if t.less(h.Item, item) { + } else if h.Item.Less(item) { h.Right, replaced = t.replaceOrInsert(h.Right, item) } else { replaced, h.Item = h.Item, item @@ -176,7 +164,7 @@ func (t *Tree) insertNoReplace(h *Node, item Item) *Node { h = walkDownRot23(h) - if t.less(item, h.Item) { + if item.Less(h.Item) { h.Left = t.insertNoReplace(h.Left, item) } else { h.Right = t.insertNoReplace(h.Right, item) @@ -312,7 +300,7 @@ func (t *Tree) delete(h *Node, item Item) (*Node, Item) { if h == nil { return nil, nil } - if t.less(item, h.Item) { + if item.Less(h.Item) { if h.Left == nil { // item not present. Nothing to delete return h, nil } @@ -325,7 +313,7 @@ func (t *Tree) delete(h *Node, item Item) (*Node, Item) { h = rotateRight(h) } // If @item equals @h.Item and no right children at @h - if !t.less(h.Item, item) && h.Right == nil { + if !h.Item.Less(item) && h.Right == nil { return nil, h.Item } // PETAR: Added 'h.Right != nil' below @@ -333,7 +321,7 @@ func (t *Tree) delete(h *Node, item Item) (*Node, Item) { h = moveRedRight(h) } // If @item equals @h.Item, and (from above) 'h.Right != nil' - if !t.less(h.Item, item) { + if !h.Item.Less(item) { var subDeleted Item h.Right, subDeleted = deleteMin(h.Right) if subDeleted == nil { diff --git a/llrb/llrb_test.go b/llrb/llrb_test.go index 1bda4dd..6b2ea1d 100644 --- a/llrb/llrb_test.go +++ b/llrb/llrb_test.go @@ -10,47 +10,39 @@ import ( "testing" ) -func IntLess(p, q interface{}) bool { - return p.(int) < q.(int) -} - -func StringLess(p, q interface{}) bool { - return p.(string) < q.(string) -} - func TestCases(t *testing.T) { - tree := New(IntLess) - tree.ReplaceOrInsert(1) - tree.ReplaceOrInsert(1) + tree := New() + tree.ReplaceOrInsert(Int(1)) + tree.ReplaceOrInsert(Int(1)) if tree.Len() != 1 { t.Errorf("expecting len 1") } - if !tree.Has(1) { + if !tree.Has(Int(1)) { t.Errorf("expecting to find key=1") } - tree.Delete(1) + tree.Delete(Int(1)) if tree.Len() != 0 { t.Errorf("expecting len 0") } - if tree.Has(1) { + if tree.Has(Int(1)) { t.Errorf("not expecting to find key=1") } - tree.Delete(1) + tree.Delete(Int(1)) if tree.Len() != 0 { t.Errorf("expecting len 0") } - if tree.Has(1) { + if tree.Has(Int(1)) { t.Errorf("not expecting to find key=1") } } func TestReverseInsertOrder(t *testing.T) { - tree := New(IntLess) + tree := New() n := 100 for i := 0; i < n; i++ { - tree.ReplaceOrInsert(n - i) + tree.ReplaceOrInsert(Int(n - i)) } c := tree.IterAscend() for j, item := 1, <-c; item != nil; j, item = j+1, <-c { diff --git a/llrb/util.go b/llrb/util.go new file mode 100644 index 0000000..63dbdb2 --- /dev/null +++ b/llrb/util.go @@ -0,0 +1,17 @@ +// Copyright 2010 Petar Maymounkov. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package llrb + +type Int int + +func (x Int) Less(than Item) bool { + return x < than.(Int) +} + +type String string + +func (x String) Less(than Item) bool { + return x < than.(String) +}