From 4bc610bb3fd6208d3a7820db6c3a5f2f14bd4ba7 Mon Sep 17 00:00:00 2001 From: emirpasic Date: Sun, 23 Sep 2018 01:35:23 +0200 Subject: [PATCH] TreeMap Floor and Ceiling functions --- maps/treemap/treemap.go | 44 +++++++----- maps/treemap/treemap_test.go | 110 +++++++++++++++-------------- trees/redblacktree/redblacktree.go | 6 +- 3 files changed, 87 insertions(+), 73 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 2105b66..a8e1dc5 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -105,26 +105,38 @@ func (m *Map) Max() (key interface{}, value interface{}) { return nil, nil } -// Floor searches the floor element in the map by key. -// Returns floor key, floor value, true if floor key is found. -// Returns nil, nil, false if floor key is not found. -func (m *Map) Floor(key interface{}) (retKey interface{}, retValue interface{}, found bool) { - ret, found := m.tree.Floor(key) - if !found { - return nil, nil, false +// Floor finds the floor key-value pair for the input key. +// In case that no floor is found, then both returned values will be nil. +// It's generally enough to check the first value (key) for nil, which determines if floor was found. +// +// Floor key is defined as the largest key that is smaller than or equal to the given key. +// A floor key may not be found, either because the map is empty, or because +// all keys in the map are larger than the given key. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Floor(key interface{}) (foundKey interface{}, foundValue interface{}) { + node, found := m.tree.Floor(key) + if found { + return node.Key, node.Value } - return ret.Key, ret.Value, true + return nil, nil } -// Ceiling searches the ceiling element in the map by key. -// Returns ceiling key, ceiling value, true if a ceiling key is found. -// Returns nil, nil, false if ceiling key is not found. -func (m *Map) Ceiling(key interface{}) (retKey interface{}, retValue interface{}, found bool) { - ret, found := m.tree.Ceiling(key) - if !found { - return nil, nil, false +// Ceiling finds the ceiling key-value pair for the input key. +// In case that no ceiling is found, then both returned values will be nil. +// It's generally enough to check the first value (key) for nil, which determines if ceiling was found. +// +// Ceiling key is defined as the smallest key that is larger than or equal to the given key. +// A ceiling key may not be found, either because the map is empty, or because +// all keys in the map are smaller than the given key. +// +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Ceiling(key interface{}) (foundKey interface{}, foundValue interface{}) { + node, found := m.tree.Ceiling(key) + if found { + return node.Key, node.Value } - return ret.Key, ret.Value, true + return nil, nil } // String returns a string representation of container diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index a08587d..0ee162e 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -118,6 +118,62 @@ func TestMapRemove(t *testing.T) { } } +func TestMapFloor(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, nil, nil, false}, + {0, nil, nil, false}, + {1, 1, "a", true}, + {2, 1, "a", true}, + {3, 3, "c", true}, + {4, 3, "c", true}, + {7, 7, "g", true}, + {8, 7, "g", true}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue := m.Floor(test[0]) + actualFound := actualKey != nil && actualValue != nil + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + +func TestMapCeiling(t *testing.T) { + m := NewWithIntComparator() + m.Put(7, "g") + m.Put(3, "c") + m.Put(1, "a") + + // key,expectedKey,expectedValue,expectedFound + tests1 := [][]interface{}{ + {-1, 1, "a", true}, + {0, 1, "a", true}, + {1, 1, "a", true}, + {2, 3, "c", true}, + {3, 3, "c", true}, + {4, 7, "g", true}, + {7, 7, "g", true}, + {8, nil, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualKey, actualValue := m.Ceiling(test[0]) + actualFound := actualKey != nil && actualValue != nil + if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { + t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) + } + } +} + func sameElements(a []interface{}, b []interface{}) bool { if len(a) != len(b) { return false @@ -289,60 +345,6 @@ func TestMapChaining(t *testing.T) { } } -func TestMapFloor(t *testing.T) { - m := NewWithIntComparator() - m.Put(7, "g") - m.Put(3, "c") - m.Put(1, "a") - - // key,expectedKey,expectedValue,expectedFound - tests1 := [][]interface{}{ - {-1, nil, nil, false}, - {0, nil, nil, false}, - {1, 1, "a", true}, - {2, 1, "a", true}, - {3, 3, "c", true}, - {4, 3, "c", true}, - {7, 7, "g", true}, - {8, 7, "g", true}, - } - - for _, test := range tests1 { - // retrievals - actualKey, actualValue, actualFound := m.Floor(test[0]) - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) - } - } -} - -func TestMapCeiling(t *testing.T) { - m := NewWithIntComparator() - m.Put(7, "g") - m.Put(3, "c") - m.Put(1, "a") - - // key,expectedKey,expectedValue,expectedFound - tests1 := [][]interface{}{ - {-1, 1, "a", true}, - {0, 1, "a", true}, - {1, 1, "a", true}, - {2, 3, "c", true}, - {3, 3, "c", true}, - {4, 7, "g", true}, - {7, 7, "g", true}, - {8, nil, nil, false}, - } - - for _, test := range tests1 { - // retrievals - actualKey, actualValue, actualFound := m.Ceiling(test[0]) - if actualKey != test[1] || actualValue != test[2] || actualFound != test[3] { - t.Errorf("Got %v, %v, %v, expected %v, %v, %v", actualKey, actualValue, actualFound, test[1], test[2], test[3]) - } - } -} - func TestMapIteratorNextOnEmpty(t *testing.T) { m := NewWithStringComparator() it := m.Iterator() diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index ecc199e..8301ffd 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -197,12 +197,12 @@ func (tree *Tree) Right() *Node { return parent } -// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. +// Floor Finds floor node of the input key, return the floor node or nil if no floor 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. +// all nodes in the tree are 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) { @@ -231,7 +231,7 @@ func (tree *Tree) Floor(key interface{}) (floor *Node, found bool) { // // 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. +// all nodes in the tree are 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) {