diff --git a/README.md b/README.md index f5a4c81..ad968b9 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Implementation of various data structures and algorithms in Go. - [Iterator](#iterator) - [IteratorWithIndex](#iteratorwithindex) - [IteratorWithKey](#iteratorwithkey) + - [ReverseIteratorWithIndex](#reverseiteratorwithindex) + - [ReverseIteratorWithKey](#reverseiteratorwithkey) - [Enumerable](#enumerable) - [EnumerableWithIndex](#enumerablewithindex) - [EnumerableWithKey](#enumerablewithkey) @@ -53,17 +55,18 @@ Containers are either ordered or unordered. All ordered containers provide [stat | Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by | | :--- | :---: | :---: | :---: | :---: | -| [ArrayList](#arraylist) | yes | yes | yes | index | +| [ArrayList](#arraylist) | yes | yes* | yes | index | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | -| [DoublyLinkedList](#doublylinkedlist) | yes | yes | yes | index | +| [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | | [HashSet](#hashset) | no | no | no | index | -| [TreeSet](#treeset) | yes | yes | yes | index | +| [TreeSet](#treeset) | yes | yes* | yes | index | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | -| [ArrayStack](#arraystack) | yes | yes | no | index | +| [ArrayStack](#arraystack) | yes | yes* | no | index | | [HashMap](#hashmap) | no | no | no | key | -| [TreeMap](#treemap) | yes | yes | yes | key | -| [RedBlackTree](#redblacktree) | yes | yes | no | key | -| [BinaryHeap](#binaryheap) | yes | yes | no | index | +| [TreeMap](#treemap) | yes | yes* | yes | key | +| [RedBlackTree](#redblacktree) | yes | yes* | no | key | +| [BinaryHeap](#binaryheap) | yes | yes* | no | index | +| | | *reversible | | | ### Lists @@ -572,12 +575,12 @@ Some data structures (e.g. TreeMap, TreeSet) require a comparator function to au Comparator is defined as: -Return values: +Return values (int): ```go --1, if a < b - 0, if a == b - 1, if a > b +negative , if a < b +zero , if a == b +positive , if a > b ``` Comparator signature: @@ -642,7 +645,7 @@ func main() { ### Iterator -All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. +All ordered containers have stateful iterators. Typically an iterator is obtained by _Iterator()_ function of an ordered container. Once obtained, iterator's _Next()_ function moves the iterator to the next element and returns true if there was a next element. If there was an element, then element's can be obtained by iterator's _Value()_ function. Depending on the ordering type, it's position can be obtained by iterator's _Index()_ or _Key()_ functions. Some containers even provide reversible iterators, essentially the same, but provide another extra _Prev()_ function that moves the iterator to the previous element and returns true if there was a previous element. #### IteratorWithIndex @@ -668,6 +671,32 @@ for it.Next() { } ``` +#### ReverseIteratorWithIndex + +A [iterator](#iterator) whose elements are referenced by an index. Typical usage: + +```go +it := list.Iterator() +for it.Next() { /* Move to end */ } +for it.Prev() { + index, value := it.Index(), it.Value() + ... +} +``` + +#### ReverseIteratorWithKey + +A [iterator](#iterator) whose elements are referenced by a key. Typical usage: + +```go +it := map.Iterator() +for it.Next() { /* Move to end */ } +for it.Prev() { + key, value := it.Key(), it.Value() + ... +} +``` + ### Enumerable Enumerable functions for ordered containers that implement [EnumerableWithIndex](#enumerablewithindex) or [EnumerableWithKey](#enumerablewithkey) interfaces. diff --git a/containers/containers.go b/containers/containers.go index 0a26c44..6e73dea 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -24,11 +24,18 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package containers provides core interfaces and functions for data structures. +// +// Container is the base interface for all data structures to implement. +// +// Iterators provide stateful iterators. +// +// Enumerable provides Ruby inspired (each, select, map, find, any?, etc.) container functions. package containers import "github.com/emirpasic/gods/utils" -// Container is base interface that all data structures implement +// Container is base interface that all data structures implement. type Container interface { Empty() bool Size() int diff --git a/containers/enumerable.go b/containers/enumerable.go index 0a09207..027de5a 100644 --- a/containers/enumerable.go +++ b/containers/enumerable.go @@ -24,9 +24,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Enumerable functions for ordered containers. -// Ruby's enumerable inspired package. - package containers // EnumerableWithIndex provides functions for ordered containers whose values can be fetched by an index. diff --git a/containers/iterator.go b/containers/iterator.go index b3d2254..c1a7c54 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -24,8 +24,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Stateful iterator pattern for ordered containers. - package containers // IteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. @@ -55,3 +53,33 @@ type IteratorWithKey interface { // Does not modify the state of the iterator. Key() interface{} } + +// ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index. +// +// Essentially it is the same as IteratorWithIndex, but provides additional Prev() function to enable traversal in reverse. +type ReverseIteratorWithIndex interface { + // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. + // If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). + // Modifies the state of the iterator. + Prev() bool + + IteratorWithIndex + // Next() bool + // Value() interface{} + // Index() int +} + +// ReverseIteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs. +// +// Essentially it is the same as IteratorWithKey, but provides additional Prev() function to enable traversal in reverse. +type ReverseIteratorWithKey interface { + // Prev moves the iterator to the previous element and returns true if there was a previous element in the container. + // If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). + // Modifies the state of the iterator. + Prev() bool + + IteratorWithKey + // Next() bool + // Value() interface{} + // Key() interface{} +} diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f471908..c08d928 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of list using a slice. +// Package arraylist implements the array list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/List_%28abstract_data_type%29 - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package arraylist import ( @@ -41,7 +42,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements in a slice @@ -194,7 +195,19 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } + return iterator.list.withinRange(iterator.index) +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } return iterator.list.withinRange(iterator.index) } diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 0dea8d8..9de67da 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,13 +333,52 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestListIteratorPrevOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } +func TestListIteratorPrev(t *testing.T) { + list := New() + list.Add("a", "b", "c") + it := list.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 58a0e4b..cb7bdfc 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of doubly linked list. +// Package doublylinkedlist implements the doubly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Doubly_linked_list - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package doublylinkedlist import ( @@ -41,7 +42,7 @@ import ( func assertInterfaceImplementation() { var _ lists.List = (*List)(nil) var _ containers.EnumerableWithIndex = (*List)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // List holds the elements, where each element points to the next and previous element @@ -315,12 +316,14 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element != nil { + if iterator.index != 0 { iterator.element = iterator.element.next } else { iterator.element = iterator.list.first @@ -328,6 +331,25 @@ func (iterator *Iterator) Next() bool { return true } +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } + if !iterator.list.withinRange(iterator.index) { + iterator.element = nil + return false + } + if iterator.index == iterator.list.size-1 { + iterator.element = iterator.list.last + } else { + iterator.element = iterator.element.prev + } + return iterator.list.withinRange(iterator.index) +} + // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index e199102..1ff73b6 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,13 +333,52 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestListIteratorPrevOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Prev() { t.Errorf("Shouldn't iterate on empty list") } } +func TestListIteratorPrev(t *testing.T) { + list := New() + list.Add("a", "b", "c") + it := list.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + func BenchmarkList(b *testing.B) { for i := 0; i < b.N; i++ { list := New() diff --git a/lists/lists.go b/lists/lists.go index ad241c2..b3d9b9a 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -16,6 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ +// Package lists provides an abstract List interface. +// +// In computer science, a list or sequence is an abstract data type that represents an ordered sequence of values, where the same value may occur more than once. An instance of a list is a computer representation of the mathematical concept of a finite sequence; the (potentially) infinite analog of a list is a stream. Lists are a basic example of containers, as they contain other values. If the same value occurs multiple times, each occurrence is considered a distinct item. +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package lists import ( diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index baf028c..f65f728 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of doubly linked list. +// Package singlylinkedlist implements the singly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Linked_list#Singly_linked_list - +// +// Reference: https://en.wikipedia.org/wiki/List_%28abstract_data_type%29 package singlylinkedlist import ( @@ -287,15 +288,17 @@ func (list *List) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.list.size { + iterator.index++ + } if !iterator.list.withinRange(iterator.index) { iterator.element = nil return false } - if iterator.element != nil { - iterator.element = iterator.element.next - } else { + if iterator.index == 0 { iterator.element = iterator.list.first + } else { + iterator.element = iterator.element.next } return true } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index c546217..53c2ad8 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -299,11 +299,21 @@ func TestListChaining(t *testing.T) { } } -func TestListIterator(t *testing.T) { +func TestListIteratorNextOnEmpty(t *testing.T) { + list := New() + it := list.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty list") + } +} + +func TestListIteratorNext(t *testing.T) { list := New() list.Add("a", "b", "c") it := list.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -323,10 +333,8 @@ func TestListIterator(t *testing.T) { t.Errorf("Too many") } } - list.Clear() - it = list.Iterator() - for it.Next() { - t.Errorf("Shouldn't iterate on empty list") + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 6ce3145..6cb8565 100644 --- a/maps/hashmap/hashmap.go +++ b/maps/hashmap/hashmap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of unorder map backed by a hash table. +// Package hashmap implements a map backed by a hash table. +// // Elements are unordered in the map. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Associative_array - +// +// Reference: http://en.wikipedia.org/wiki/Associative_array package hashmap import ( diff --git a/maps/maps.go b/maps/maps.go index 2e82434..93f8bc0 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -24,6 +24,17 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package maps provides an abstract Map interface. +// +// In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears just once in the collection. +// +// Operations associated with this data type allow: +// - the addition of a pair to the collection +// - the removal of a pair from the collection +// - the modification of an existing pair +// - the lookup of a value associated with a particular key +// +// Reference: https://en.wikipedia.org/wiki/Associative_array package maps import "github.com/emirpasic/gods/containers" diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index 4b8558d..f1640bf 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of order map backed by red-black tree. +// Package treemap implements a map backed by red-black tree. +// // Elements are ordered by key in the map. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Associative_array - +// +// Reference: http://en.wikipedia.org/wiki/Associative_array package treemap import ( @@ -41,7 +43,7 @@ import ( func assertInterfaceImplementation() { var _ maps.Map = (*Map)(nil) var _ containers.EnumerableWithKey = (*Map)(nil) - var _ containers.IteratorWithKey = (*Iterator)(nil) + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } // Map holds the elements in a red-black tree @@ -143,6 +145,13 @@ func (iterator *Iterator) Next() bool { return iterator.iterator.Next() } +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + return iterator.iterator.Prev() +} + // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index c081431..ac4d778 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -311,14 +311,34 @@ func TestMapChaining(t *testing.T) { } } -func TestMapIterator(t *testing.T) { +func TestMapIteratorNextOnEmpty(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorPrevOnEmpty(t *testing.T) { + m := NewWithStringComparator() + it := m.Iterator() + it = m.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorNext(t *testing.T) { m := NewWithStringComparator() m.Put("c", 3) m.Put("a", 1) m.Put("b", 2) it := m.Iterator() + count := 0 for it.Next() { + count++ key := it.Key() value := it.Value() switch key { @@ -337,12 +357,52 @@ func TestMapIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - m.Clear() - it = m.Iterator() +func TestMapIteratorPrev(t *testing.T) { + m := NewWithStringComparator() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + + it := m.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty map") + } + countDown := m.Size() + for it.Prev() { + countDown-- + key := it.Key() + value := it.Value() + switch key { + case "a": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "c": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 41b78c7..e3f44c7 100644 --- a/sets/hashset/hashset.go +++ b/sets/hashset/hashset.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of set backed by a hash table. +// Package hashset implements a set backed by a hash table. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 - package hashset import ( diff --git a/sets/sets.go b/sets/sets.go index fd4fc08..b0ae988 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,6 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ +// Package sets provides an abstract Set interface. +// +// In computer science, a set is an abstract data type that can store certain values and no repeated values. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set. +// +// Reference: https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package sets import "github.com/emirpasic/gods/containers" diff --git a/sets/treeset/treeset.go b/sets/treeset/treeset.go index 7b09138..3a0de08 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -16,10 +16,11 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Implementation of an ordered set backed by a red-black tree. +// Package treeset implements a tree backed by a red-black tree. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 - +// +// Reference: http://en.wikipedia.org/wiki/Set_%28abstract_data_type%29 package treeset import ( @@ -34,7 +35,7 @@ import ( func assertInterfaceImplementation() { var _ sets.Set = (*Set)(nil) var _ containers.EnumerableWithIndex = (*Set)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Set holds elements in a red-black tree @@ -109,21 +110,34 @@ func (set *Set) Values() []interface{} { type Iterator struct { index int iterator rbt.Iterator + tree *rbt.Tree } // Iterator holding the iterator's state func (set *Set) Iterator() Iterator { - return Iterator{index: -1, iterator: set.tree.Iterator()} + return Iterator{index: -1, iterator: set.tree.Iterator(), tree: set.tree} } // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.tree.Size() { + iterator.index++ + } return iterator.iterator.Next() } +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.iterator.Prev() +} + // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 14bb4de..ccdb16c 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -192,12 +192,29 @@ func TestSetChaining(t *testing.T) { set.Add("c", "a", "b") } -func TestSetIterator(t *testing.T) { +func TestSetIteratorNextOnEmpty(t *testing.T) { set := NewWithStringComparator() - set.Add("c", "a", "b") + it := set.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty set") + } +} + +func TestSetIteratorPrevOnEmpty(t *testing.T) { + set := NewWithStringComparator() + it := set.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty set") + } +} +func TestSetIteratorNext(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") it := set.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -216,12 +233,48 @@ func TestSetIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - set.Clear() - it = set.Iterator() +func TestSetIteratorPrev(t *testing.T) { + set := NewWithStringComparator() + set.Add("c", "a", "b") + it := set.Iterator() + for it.Prev() { + } + count := 0 for it.Next() { - t.Errorf("Shouldn't iterate on empty set") + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 1e69adc..ece76a9 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -24,10 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of stack backed by ArrayList. +// Package arraystack implements a stack backed by array list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 - +// +// Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Array package arraystack import ( @@ -40,7 +41,7 @@ import ( func assertInterfaceImplementation() { var _ stacks.Stack = (*Stack)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Stack holds elements in an array-list @@ -112,7 +113,19 @@ func (stack *Stack) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.stack.Size() { + iterator.index++ + } + return iterator.stack.withinRange(iterator.index) +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } return iterator.stack.withinRange(iterator.index) } diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 42d7d6a..fad4ac0 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -92,15 +92,24 @@ func TestStackPop(t *testing.T) { } } -func TestStackIterator(t *testing.T) { +func TestStackIteratorOnEmpty(t *testing.T) { + stack := New() + it := stack.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty stack") + } +} + +func TestStackIteratorNext(t *testing.T) { stack := New() stack.Push("a") stack.Push("b") stack.Push("c") - // Iterator it := stack.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -119,11 +128,51 @@ func TestStackIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } - stack.Clear() - it = stack.Iterator() + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestStackIteratorPrev(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + it := stack.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 843e159..75f1948 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -24,11 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of stack backed by our singly linked list. -// Used by red-black tree during in-order traversal. +// Package linkedliststack implements a stack backed by a singly-linked list. +// // Structure is not thread safe. -// References: http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 - +// +// Reference:https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29#Linked_list package linkedliststack import ( @@ -108,7 +108,9 @@ func (stack *Stack) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.stack.Size() { + iterator.index++ + } return iterator.stack.withinRange(iterator.index) } diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index c9b097a..4fb0002 100644 --- a/stacks/linkedliststack/linkedliststack_test.go +++ b/stacks/linkedliststack/linkedliststack_test.go @@ -100,7 +100,9 @@ func TestStackIterator(t *testing.T) { // Iterator it := stack.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -119,7 +121,14 @@ func TestStackIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } + stack.Clear() it = stack.Iterator() for it.Next() { diff --git a/stacks/stacks.go b/stacks/stacks.go index ceaf6f1..a580d36 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -24,6 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package stacks provides an abstract Stack interface. +// +// In computer science, a stack is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the most recently added element that was not yet removed. The order in which elements come off a stack gives rise to its alternative name, LIFO (for last in, first out). Additionally, a peek operation may give access to the top without modifying the stack. +// +// Reference: https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29 package stacks import "github.com/emirpasic/gods/containers" diff --git a/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 8a97d5a..0e5942f 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of binary heap backed by ArrayList. +// Package binaryheap implements a binary heap backed by array list. +// // Comparator defines this heap as either min or max heap. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Binary_heap - package binaryheap import ( @@ -42,7 +44,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Heap)(nil) - var _ containers.IteratorWithIndex = (*Iterator)(nil) + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) } // Heap holds elements in an array-list @@ -127,7 +129,19 @@ func (heap *Heap) Iterator() Iterator { // If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - iterator.index++ + if iterator.index < iterator.heap.Size() { + iterator.index++ + } + return iterator.heap.withinRange(iterator.index) +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } return iterator.heap.withinRange(iterator.index) } diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go index 7699634..d72375a 100644 --- a/trees/binaryheap/binaryheap_test.go +++ b/trees/binaryheap/binaryheap_test.go @@ -107,19 +107,24 @@ func TestBinaryHeapRandom(t *testing.T) { } } -func TestBinaryHeapIterator(t *testing.T) { +func TestBinaryHeapIteratorOnEmpty(t *testing.T) { heap := NewWithIntComparator() - - if actualValue := heap.Empty(); actualValue != true { - t.Errorf("Got %v expected %v", actualValue, true) + it := heap.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty heap") } +} +func TestBinaryHeapIteratorNext(t *testing.T) { + heap := NewWithIntComparator() heap.Push(3) // [3] heap.Push(2) // [2,3] heap.Push(1) // [1,3,2](2 swapped with 1, hence last) it := heap.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -138,12 +143,51 @@ func TestBinaryHeapIterator(t *testing.T) { default: t.Errorf("Too many") } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} - heap.Clear() - it = heap.Iterator() +func TestBinaryHeapIteratorPrev(t *testing.T) { + heap := NewWithIntComparator() + heap.Push(3) // [3] + heap.Push(2) // [2,3] + heap.Push(1) // [1,3,2](2 swapped with 1, hence last) + + it := heap.Iterator() for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) } } diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index abcdffd..cf68bab 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -24,11 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Implementation of Red-black tree. +// Package redblacktree implements a red-black tree. +// // Used by TreeSet and TreeMap. +// // Structure is not thread safe. +// // References: http://en.wikipedia.org/wiki/Red%E2%80%93black_tree - package redblacktree import ( @@ -41,7 +43,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Tree)(nil) - var _ containers.IteratorWithKey = (*Iterator)(nil) + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } type color bool @@ -279,37 +281,65 @@ func (tree *Tree) Clear() { // Iterator holding the iterator's state type Iterator struct { tree *Tree - left *Node + node *Node } // Iterator returns a stateful iterator whose elements are key/value pairs. func (tree *Tree) Iterator() Iterator { - return Iterator{tree: tree, left: nil} + return Iterator{tree: tree, node: nil} } // Next moves the iterator to the next element and returns true if there was a next element in the container. // If Next() returns true, then next element's key and value can be retrieved by Key() and Value(). // Modifies the state of the iterator. func (iterator *Iterator) Next() bool { - if iterator.left == nil { - iterator.left = iterator.tree.Left() - return iterator.left != nil - } - if iterator.left.Right != nil { - iterator.left = iterator.left.Right - for iterator.left.Left != nil { - iterator.left = iterator.left.Left + if iterator.node == nil { + iterator.node = iterator.tree.Left() + return iterator.node != nil + } + if iterator.node.Right != nil { + iterator.node = iterator.node.Right + for iterator.node.Left != nil { + iterator.node = iterator.node.Left + } + return true + } + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) <= 0 { + return true + } + } + iterator.node = node // fix: if parent didn't satisfy the comparator criteria + } + return false +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.node == nil { + return false + } + if iterator.node.Left != nil { + iterator.node = iterator.node.Left + for iterator.node.Right != nil { + iterator.node = iterator.node.Right } return true } - if iterator.left.Parent != nil { - key := iterator.left.Key - for iterator.left.Parent != nil { - iterator.left = iterator.left.Parent - if iterator.tree.Comparator(key, iterator.left.Key) <= 0 { + if iterator.node.Parent != nil { + node := iterator.node + for iterator.node.Parent != nil { + iterator.node = iterator.node.Parent + if iterator.tree.Comparator(node.Key, iterator.node.Key) >= 0 { return true } } + iterator.node = node // fix: if parent didn't satisfy the comparator criteria } return false } @@ -317,13 +347,13 @@ func (iterator *Iterator) Next() bool { // Value returns the current element's value. // Does not modify the state of the iterator. func (iterator *Iterator) Value() interface{} { - return iterator.left.Value + return iterator.node.Value } // Key returns the current element's key. // Does not modify the state of the iterator. func (iterator *Iterator) Key() interface{} { - return iterator.left.Key + return iterator.node.Key } // String returns a string representation of container diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 96fa4e1..3f5987a 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -206,7 +206,23 @@ func TestRedBlackTreeCeilingAndFloor(t *testing.T) { } } -func TestRedBlackTreeIterator1(t *testing.T) { +func TestRedBlackTreeIteratorNextOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestRedBlackTreeIteratorPrevOnEmpty(t *testing.T) { + tree := NewWithIntComparator() + it := tree.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty tree") + } +} + +func TestRedBlackTreeIterator1Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") tree.Put(6, "f") @@ -216,29 +232,76 @@ func TestRedBlackTreeIterator1(t *testing.T) { tree.Put(1, "x") tree.Put(2, "b") tree.Put(1, "a") //overwrite - + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 it := tree.Iterator() count := 0 for it.Next() { count++ - index := it.Key() - switch index { + key := it.Key() + switch key { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 7; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } -func TestRedBlackTreeIterator2(t *testing.T) { +func TestRedBlackTreeIterator1Prev(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(5, "e") + tree.Put(6, "f") + tree.Put(7, "g") + tree.Put(3, "c") + tree.Put(4, "d") + tree.Put(1, "x") + tree.Put(2, "b") + tree.Put(1, "a") //overwrite + // │ ┌── 7 + // └── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} + +func TestRedBlackTreeIterator2Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -247,50 +310,142 @@ func TestRedBlackTreeIterator2(t *testing.T) { count := 0 for it.Next() { count++ - index := it.Key() - switch index { + key := it.Key() + switch key { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 3; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } -func TestRedBlackTreeIterator3(t *testing.T) { +func TestRedBlackTreeIterator2Prev(t *testing.T) { tree := NewWithIntComparator() + tree.Put(3, "c") + tree.Put(1, "a") + tree.Put(2, "b") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} +func TestRedBlackTreeIterator3Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(1, "a") it := tree.Iterator() + count := 0 for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") + count++ + key := it.Key() + switch key { + case count: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} +func TestRedBlackTreeIterator3Prev(t *testing.T) { + tree := NewWithIntComparator() tree.Put(1, "a") + it := tree.Iterator() + for it.Next() { + } + countDown := tree.size + for it.Prev() { + countDown-- + key := it.Key() + switch key { + case countDown: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + } + // one less that in Next(), thus "1" + if actualValue, expectedValue := countDown, 1; actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } +} - it = tree.Iterator() +func TestRedBlackTreeIterator4Next(t *testing.T) { + tree := NewWithIntComparator() + tree.Put(13, 5) + tree.Put(8, 3) + tree.Put(17, 7) + tree.Put(1, 1) + tree.Put(11, 4) + tree.Put(15, 6) + tree.Put(25, 9) + tree.Put(6, 2) + tree.Put(22, 8) + tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() count := 0 for it.Next() { count++ - index := it.Key() - switch index { + value := it.Value() + switch value { case count: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := value, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } default: - if actualValue, expectedValue := index, count; actualValue != expectedValue { + if actualValue, expectedValue := value, count; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 1; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } @@ -307,11 +462,22 @@ func TestRedBlackTreeIterator4(t *testing.T) { tree.Put(6, 2) tree.Put(22, 8) tree.Put(27, 10) - + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 it := tree.Iterator() - count := 0 + count := tree.Size() for it.Next() { - count++ + } + for it.Prev() { + count-- value := it.Value() switch value { case count: @@ -324,7 +490,8 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } } - if actualValue, expectedValue := count, 10; actualValue != expectedValue { + // one less that in Next(), thus "1" + if actualValue, expectedValue := count, 1; actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } } diff --git a/trees/trees.go b/trees/trees.go index 055c308..2b235c1 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -24,6 +24,11 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +// Package trees provides an abstract Tree interface. +// +// In computer science, a tree is a widely used abstract data type (ADT) or data structure implementing this ADT that simulates a hierarchical tree structure, with a root value and subtrees of children with a parent node, represented as a set of linked nodes. +// +// Reference: https://en.wikipedia.org/wiki/Tree_%28data_structure%29 package trees import "github.com/emirpasic/gods/containers" diff --git a/utils/comparator.go b/utils/comparator.go index 6ce6829..7dfd698 100644 --- a/utils/comparator.go +++ b/utils/comparator.go @@ -29,10 +29,10 @@ package utils // Comparator will make type assertion (see IntComparator for example), // which will panic if a or b are not of the asserted type. // -// Should return: -// -1, if a < b -// 0, if a == b -// 1, if a > b +// Should return a number: +// negative , if a < b +// zero , if a == b +// positive , if a > b type Comparator func(a, b interface{}) int // IntComparator provides a basic comparison on ints diff --git a/utils/sort.go b/utils/sort.go index 3cf8c1f..154ce3d 100644 --- a/utils/sort.go +++ b/utils/sort.go @@ -24,14 +24,13 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Util methods for sorting a slice of values with respect to the comparator - package utils import "sort" -// Sort sorts values (in-place) -// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices) +// Sort sorts values (in-place) with respect to the given comparator. +// +// Uses Go's sort (hybrid of quicksort for large and then insertion sort for smaller slices). func Sort(values []interface{}, comparator Comparator) { sort.Sort(sortable{values, comparator}) } diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..077c1f0 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,32 @@ +/* +Copyright (c) 2015, Emir Pasic +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Package utils provides common utility functions. +// +// Provided functionalities: +// - sorting +// - comparators +package utils