From d13e3d6b6a9f8e541162c9ba7ede1d4ac5b687cd Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Mon, 13 Jun 2016 00:52:16 +0200 Subject: [PATCH] - Add Left(), Right(), Floor() and Ceiling() function to the red black tree with test and documentation update --- README.md | 6 ++ examples/redblacktreeextended.go | 84 ------------------- trees/redblacktree/redblacktree.go | 106 +++++++++++++++++------- trees/redblacktree/redblacktree_test.go | 56 +++++++++++++ 4 files changed, 136 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index b26838c..0d22bfa 100644 --- a/README.md +++ b/README.md @@ -471,6 +471,12 @@ func main() { tree.Clear() // empty tree.Empty() // true tree.Size() // 0 + + // Other: + tree.Left() // gets the left-most (min) node + tree.Right() // get the right-most (max) node + tree.Floor(1) // get the floor node + tree.Ceiling(1) // get the ceiling node } ``` diff --git a/examples/redblacktreeextended.go b/examples/redblacktreeextended.go index 17855c9..fbb8d6c 100644 --- a/examples/redblacktreeextended.go +++ b/examples/redblacktreeextended.go @@ -95,64 +95,6 @@ func (tree *RedBlackTreeExtended) getMaxFromNode(node *rbt.Node) (foundNode *rbt } } -// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. -// Second return parameter is true if ceiling was found, otherwise false. -// -// Ceiling node is defined as the smallest node that is larger than or equal to the given node. -// A ceiling node may not be found, either because the tree is empty, or because -// all nodes in the tree is smaller than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Ceiling(key interface{}) (ceiling *rbt.Node, found bool) { - found = false - node := tree.Root - for node != nil { - compare := tree.Comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - ceiling, found = node, true - node = node.Left - case compare > 0: - node = node.Right - } - } - if found { - return ceiling, true - } - return nil, false -} - -// Find floor node of the input key, return the floor node or nil if no ceiling is found. -// Second return parameter is true if floor was found, otherwise false. -// -// Floor node is defined as the largest node that is smaller than or equal to the given node. -// A floor node may not be found, either because the tree is empty, or because -// all nodes in the tree is larger than the given node. -// -// Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *RedBlackTreeExtended) Floor(key interface{}) (floor *rbt.Node, found bool) { - found = false - node := tree.Root - for node != nil { - compare := tree.Comparator(key, node.Key) - switch { - case compare == 0: - return node, true - case compare < 0: - node = node.Left - case compare > 0: - floor, found = node, true - node = node.Right - } - } - if found { - return floor, true - } - return nil, false -} - func print(tree *RedBlackTreeExtended) { max, _ := tree.GetMax() min, _ := tree.GetMin() @@ -190,30 +132,4 @@ func RedBlackTreeExtendedExample() { // Value for min key: c // RedBlackTree // └── 3 - - // Ceiling and Floor functions - tree = RedBlackTreeExtended{rbt.NewWithIntComparator()} - tree.Put(1, "a") - tree.Put(2, "b") - tree.Put(4, "d") - tree.Put(6, "f") - tree.Put(7, "g") - - //index, ceiling, floor - testValues := [][]interface{}{ - {0, 1, nil}, - {1, 1, 1}, - {2, 2, 2}, - {3, 4, 2}, - {4, 4, 4}, - {5, 6, 4}, - {6, 6, 6}, - {7, 7, 7}, - {8, nil, 7}, - } - for _, tt := range testValues { - actualCeiling, _ := tree.Ceiling(tt[0]) - actualFloor, _ := tree.Floor(tt[0]) - fmt.Printf("test key %d, expected (%d, %d), actual (%d, %d)\n", tt[0], tt[1], tt[2], actualCeiling.Key, actualFloor.Key) - } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 67f83b2..2fe165b 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -186,22 +186,84 @@ func (tree *Tree) Values() []interface{} { return values } -// Returns the left-most key. -func (tree *Tree) Left() interface{} { - left := tree.leftNode() - if left == nil { - return nil +// Returns the left-most (min) node or nil if tree is empty. +func (tree *Tree) Left() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Left } - return left.Key + return parent } -// Returns the right-most key. -func (tree *Tree) Right() interface{} { - right := tree.rightNode() - if right == nil { - return nil +// Returns the right-most (max) node or nil if tree is empty. +func (tree *Tree) Right() *Node { + var parent *Node + current := tree.Root + for current != nil { + parent = current + current = current.Right + } + return parent +} + +// Find floor node of the input key, return the floor node or nil if no ceiling is found. +// Second return parameter is true if floor was found, otherwise false. +// +// Floor node is defined as the largest node that is smaller than or equal to the given node. +// A floor node may not be found, either because the tree is empty, or because +// all nodes in the tree is larger than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + node = node.Left + case compare > 0: + floor, found = node, true + node = node.Right + } + } + if found { + return floor, true + } + return nil, false +} + +// Find ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Second return parameter is true if ceiling was found, otherwise false. +// +// Ceiling node is defined as the smallest node that is larger than or equal to the given node. +// A ceiling node may not be found, either because the tree is empty, or because +// all nodes in the tree is smaller than the given node. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (tree *Tree) Ceiling(key interface{}) (ceiling *Node, found bool) { + found = false + node := tree.Root + for node != nil { + compare := tree.Comparator(key, node.Key) + switch { + case compare == 0: + return node, true + case compare < 0: + ceiling, found = node, true + node = node.Left + case compare > 0: + node = node.Right + } } - return right.Key + if found { + return ceiling, true + } + return nil, false } // Removes all nodes from the tree. @@ -250,26 +312,6 @@ func (tree *Tree) inOrder() []*Node { return nodes } -func (tree *Tree) leftNode() *Node { - var parent *Node - current := tree.Root - for current != nil { - parent = current - current = current.Left - } - return parent -} - -func (tree *Tree) rightNode() *Node { - var parent *Node - current := tree.Root - for current != nil { - parent = current - current = current.Right - } - return parent -} - func output(node *Node, prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 050bca5..20a287c 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -60,6 +60,38 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + // test Left() + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Left().Key), "1"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left().Value), "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Right() + if actualValue, expectedValue := fmt.Sprintf("%d", tree.Right().Key), "7"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right().Value), "g"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // test Floor() + if node, found := tree.Floor(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Floor(0); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + // test Ceiling() + if node, found := tree.Ceiling(4); node.Key != 4 || !found { + t.Errorf("Got %v expected %v", node.Key, 4) + } + if node, found := tree.Ceiling(8); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + // key,expectedValue,expectedFound tests1 := [][]interface{}{ {1, "a", true}, @@ -97,6 +129,11 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, expectedValue) } + // test Values() + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s", tree.Values()...), "abcd"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + // Test Size() if actualValue := tree.Size(); actualValue != 4 { t.Errorf("Got %v expected %v", actualValue, 7) @@ -158,6 +195,25 @@ func TestRedBlackTree(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + // test Left() + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Left()), ""; actualValue != expectedValue { + t.Errorf("Got %s expected %s", actualValue, expectedValue) + } + + // test Right() + if actualValue, expectedValue := fmt.Sprintf("%s", tree.Right()), ""; actualValue != expectedValue { + t.Errorf("Got %s expected %s", actualValue, expectedValue) + } + + // test Floor() + if node, found := tree.Floor(1); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } + + // test Ceiling() + if node, found := tree.Ceiling(1); node != nil || found { + t.Errorf("Got %v expected %v", node, "") + } } func BenchmarkRedBlackTree(b *testing.B) {