From 59bebe43ce49653e95d8a40af2a58754ef33c92c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 17:02:21 +0200 Subject: [PATCH 1/6] - update all documentation to be in godoc style --- README.md | 8 ++++---- containers/containers.go | 9 ++++++++- containers/enumerable.go | 3 --- containers/iterator.go | 2 -- lists/arraylist/arraylist.go | 7 ++++--- lists/doublylinkedlist/doublylinkedlist.go | 7 ++++--- lists/lists.go | 5 +++++ lists/singlylinkedlist/singlylinkedlist.go | 7 ++++--- maps/hashmap/hashmap.go | 8 +++++--- maps/maps.go | 11 +++++++++++ maps/treemap/treemap.go | 8 +++++--- sets/hashset/hashset.go | 5 +++-- sets/sets.go | 5 +++++ sets/treeset/treeset.go | 7 ++++--- stacks/arraystack/arraystack.go | 7 ++++--- stacks/linkedliststack/linkedliststack.go | 8 ++++---- stacks/stacks.go | 5 +++++ trees/binaryheap/binaryheap.go | 6 ++++-- trees/redblacktree/redblacktree.go | 6 ++++-- trees/trees.go | 5 +++++ utils/comparator.go | 8 ++++---- utils/sort.go | 7 +++---- 22 files changed, 95 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index f5a4c811..4c6006b3 100644 --- a/README.md +++ b/README.md @@ -572,12 +572,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: diff --git a/containers/containers.go b/containers/containers.go index 0a26c44e..91ca0463 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 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 0a092070..027de5a8 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 b3d22543..fd2d4d47 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. diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f471908d..ad0fc092 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 ( diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index 58a0e4bf..3f976479 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 ( diff --git a/lists/lists.go b/lists/lists.go index ad241c26..539d14eb 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 abstract List interface for that all concrete lists should implement. +// +// 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 baf028c4..953ab8b9 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 ( diff --git a/maps/hashmap/hashmap.go b/maps/hashmap/hashmap.go index 6ce31458..6cb8565c 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 2e82434e..809f138b 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 abstract Map interface for that all concrete maps should implement. +// +// 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 4b8558da..efa46e43 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 ( diff --git a/sets/hashset/hashset.go b/sets/hashset/hashset.go index 41b78c7b..e3f44c71 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 fd4fc084..af4aa22c 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 abstract Set interface for that all concrete sets should implement. +// +// 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 7b091387..a1b8ee93 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 ( diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index 1e69adc9..caacf4d2 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 ( diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 843e159d..858033ed 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 ( diff --git a/stacks/stacks.go b/stacks/stacks.go index ceaf6f17..749bd3f2 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 abstract Stack interface for that all concrete stacks should implement. +// +// 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 8a97d5a0..2bad245d 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 ( diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index abcdffd3..adcd4ec2 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 ( diff --git a/trees/trees.go b/trees/trees.go index 055c3083..069a8806 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 abstract Tree interface for that all concrete trees should implement. +// +// 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 6ce68292..7dfd6988 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 3cf8c1fa..154ce3d5 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}) } From d7a31571cc977b8cd232dc8c66533b554990b67c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 18:17:48 +0200 Subject: [PATCH 2/6] - add reversible iterators to lists (array list and doubly-linked list) - documentation and tests updates --- README.md | 37 ++++++++++-- containers/containers.go | 2 +- containers/iterator.go | 30 ++++++++++ lists/arraylist/arraylist.go | 16 +++++- lists/arraylist/arraylist_test.go | 57 +++++++++++++++++-- lists/doublylinkedlist/doublylinkedlist.go | 27 ++++++++- .../doublylinkedlist/doublylinkedlist_test.go | 57 +++++++++++++++++-- lists/lists.go | 2 +- lists/singlylinkedlist/singlylinkedlist.go | 10 ++-- .../singlylinkedlist/singlylinkedlist_test.go | 18 ++++-- maps/maps.go | 2 +- sets/sets.go | 2 +- stacks/stacks.go | 2 +- trees/trees.go | 2 +- utils/utils.go | 32 +++++++++++ 15 files changed, 264 insertions(+), 32 deletions(-) create mode 100644 utils/utils.go diff --git a/README.md b/README.md index 4c6006b3..2cf8d6e3 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,9 +55,9 @@ 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 | -| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | -| [DoublyLinkedList](#doublylinkedlist) | yes | yes | yes | index | +| [ArrayList](#arraylist) | yes | yes* | yes | index | +| [SinglyLinkedList](#singlylinkedlist) | yes | yes* | yes | index | +| [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | | [HashSet](#hashset) | no | no | no | index | | [TreeSet](#treeset) | yes | yes | yes | index | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | @@ -64,6 +66,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat | [TreeMap](#treemap) | yes | yes | yes | key | | [RedBlackTree](#redblacktree) | yes | yes | no | key | | [BinaryHeap](#binaryheap) | yes | yes | no | index | +| | | *reversible | | | ### Lists @@ -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 91ca0463..6e73dea6 100644 --- a/containers/containers.go +++ b/containers/containers.go @@ -24,7 +24,7 @@ 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 data structures. +// Package containers provides core interfaces and functions for data structures. // // Container is the base interface for all data structures to implement. // diff --git a/containers/iterator.go b/containers/iterator.go index fd2d4d47..c1a7c545 100644 --- a/containers/iterator.go +++ b/containers/iterator.go @@ -53,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 ad0fc092..c08d928b 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -42,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 @@ -195,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 0dea8d8a..9de67da9 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 3f976479..cb7bdfc5 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -42,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 @@ -316,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 @@ -329,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 e199102f..1ff73b67 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 539d14eb..b3d9b9af 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -16,7 +16,7 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Package lists provides abstract List interface for that all concrete lists should implement. +// 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. // diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index 953ab8b9..f65f7282 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -288,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 c5462177..53c2ad8f 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/maps.go b/maps/maps.go index 809f138b..93f8bc0f 100644 --- a/maps/maps.go +++ b/maps/maps.go @@ -24,7 +24,7 @@ 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 abstract Map interface for that all concrete maps should implement. +// 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. // diff --git a/sets/sets.go b/sets/sets.go index af4aa22c..b0ae9884 100644 --- a/sets/sets.go +++ b/sets/sets.go @@ -16,7 +16,7 @@ License along with this library. See the file LICENSE included with this distribution for more information. */ -// Package sets provides abstract Set interface for that all concrete sets should implement. +// 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. // diff --git a/stacks/stacks.go b/stacks/stacks.go index 749bd3f2..a580d36e 100644 --- a/stacks/stacks.go +++ b/stacks/stacks.go @@ -24,7 +24,7 @@ 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 abstract Stack interface for that all concrete stacks should implement. +// 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. // diff --git a/trees/trees.go b/trees/trees.go index 069a8806..2b235c16 100644 --- a/trees/trees.go +++ b/trees/trees.go @@ -24,7 +24,7 @@ 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 abstract Tree interface for that all concrete trees should implement. +// 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. // diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..077c1f0a --- /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 From b304f5eb5843c37332c3c0f824b5ac5d0eb94e2b Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 19:11:20 +0200 Subject: [PATCH 3/6] - add reversible iterators to array stack --- README.md | 12 +++--- maps/treemap/treemap_test.go | 8 ++++ sets/treeset/treeset_test.go | 8 ++++ stacks/arraystack/arraystack.go | 16 +++++++- stacks/arraystack/arraystack_test.go | 41 ++++++++++++++++++- .../linkedliststack/linkedliststack_test.go | 9 ++++ 6 files changed, 85 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2cf8d6e3..ad968b90 100644 --- a/README.md +++ b/README.md @@ -56,16 +56,16 @@ 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 | -| [SinglyLinkedList](#singlylinkedlist) | yes | yes* | yes | index | +| [SinglyLinkedList](#singlylinkedlist) | 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 diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index c0814314..66f411c4 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -318,7 +318,9 @@ func TestMapIterator(t *testing.T) { m.Put("b", 2) it := m.Iterator() + count := 0 for it.Next() { + count++ key := it.Key() value := it.Value() switch key { @@ -337,6 +339,12 @@ 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() diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go index 14bb4dea..31428ac8 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -197,7 +197,9 @@ func TestSetIterator(t *testing.T) { set.Add("c", "a", "b") it := set.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -216,6 +218,12 @@ 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() diff --git a/stacks/arraystack/arraystack.go b/stacks/arraystack/arraystack.go index caacf4d2..ece76a9b 100644 --- a/stacks/arraystack/arraystack.go +++ b/stacks/arraystack/arraystack.go @@ -41,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 @@ -113,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 42d7d6a6..98af62c3 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -98,9 +98,11 @@ func TestStackIterator(t *testing.T) { stack.Push("b") stack.Push("c") - // Iterator + // Iterator (next) it := stack.Iterator() + count := 0 for it.Next() { + count++ index := it.Index() value := it.Value() switch index { @@ -119,7 +121,44 @@ 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) } + + // Iterator (prev) + 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) + } + stack.Clear() it = stack.Iterator() for it.Next() { diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go index c9b097af..4fb00024 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() { From ae143689c625cac225765fa5dcf6c086a133e01f Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 19:26:08 +0200 Subject: [PATCH 4/6] - add reversible iterators to binary heap --- stacks/arraystack/arraystack_test.go | 30 ++++++++---- stacks/linkedliststack/linkedliststack.go | 4 +- trees/binaryheap/binaryheap.go | 16 ++++++- trees/binaryheap/binaryheap_test.go | 58 ++++++++++++++++++++--- 4 files changed, 88 insertions(+), 20 deletions(-) diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go index 98af62c3..fad4ac08 100644 --- a/stacks/arraystack/arraystack_test.go +++ b/stacks/arraystack/arraystack_test.go @@ -92,13 +92,20 @@ 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 (next) it := stack.Iterator() count := 0 for it.Next() { @@ -128,9 +135,18 @@ func TestStackIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } +} - // Iterator (prev) - count = 0 +func TestStackIteratorPrev(t *testing.T) { + stack := New() + stack.Push("a") + stack.Push("b") + stack.Push("c") + + it := stack.Iterator() + for it.Next() { + } + count := 0 for it.Prev() { count++ index := it.Index() @@ -158,12 +174,6 @@ func TestStackIterator(t *testing.T) { if actualValue, expectedValue := count, 3; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } - - stack.Clear() - it = stack.Iterator() - for it.Next() { - t.Errorf("Shouldn't iterate on empty stack") - } } func BenchmarkStack(b *testing.B) { diff --git a/stacks/linkedliststack/linkedliststack.go b/stacks/linkedliststack/linkedliststack.go index 858033ed..75f19480 100644 --- a/stacks/linkedliststack/linkedliststack.go +++ b/stacks/linkedliststack/linkedliststack.go @@ -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/trees/binaryheap/binaryheap.go b/trees/binaryheap/binaryheap.go index 2bad245d..0e5942f4 100644 --- a/trees/binaryheap/binaryheap.go +++ b/trees/binaryheap/binaryheap.go @@ -44,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 @@ -129,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 76996341..d72375a3 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) } } From 178bc76d62c2a44f18925823bbdafd804a292150 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 20:45:43 +0200 Subject: [PATCH 5/6] - add reversible iterators to red-black tree --- trees/redblacktree/redblacktree.go | 64 +++++--- trees/redblacktree/redblacktree_test.go | 193 +++++++++++++++++++++--- 2 files changed, 215 insertions(+), 42 deletions(-) diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index adcd4ec2..cf68bab3 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -43,7 +43,7 @@ import ( func assertInterfaceImplementation() { var _ trees.Tree = (*Tree)(nil) - var _ containers.IteratorWithKey = (*Iterator)(nil) + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) } type color bool @@ -281,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.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 +} + +// 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.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 } @@ -319,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 96fa4e1d..377ee9e2 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 := 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 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 := index, count; actualValue != expectedValue { + if actualValue, expectedValue := key, countDown; actualValue != expectedValue { t.Errorf("Got %v expected %v", actualValue, expectedValue) } } } - if actualValue, expectedValue := count, 7; 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 TestRedBlackTreeIterator2(t *testing.T) { +func TestRedBlackTreeIterator2Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(3, "c") tree.Put(1, "a") @@ -247,50 +310,99 @@ 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() { - t.Errorf("Shouldn't iterate on empty stack") } + 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() + 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, 1; 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) } } @@ -308,7 +420,20 @@ func TestRedBlackTreeIterator4(t *testing.T) { tree.Put(22, 8) tree.Put(27, 10) + // │ ┌── 27 + // │ ┌── 25 + // │ │ └── 22 + // │ ┌── 17 + // │ │ └── 15 + // └── 13 + // │ ┌── 11 + // └── 8 + // │ ┌── 6 + // └── 1 + it := tree.Iterator() + + // Iterator (next) count := 0 for it.Next() { count++ @@ -324,7 +449,27 @@ func TestRedBlackTreeIterator4(t *testing.T) { } } } - if actualValue, expectedValue := count, 10; actualValue != expectedValue { + if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { + t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) + } + + // Iterator (prev) + for it.Prev() { + count-- + value := it.Value() + switch value { + case count: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", 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) } } From eb4bb224e398363dd251b8b884f5bdbfc467a55c Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Sat, 25 Jun 2016 21:01:33 +0200 Subject: [PATCH 6/6] - add reversible iterators to tree set and tree map --- maps/treemap/treemap.go | 9 +++- maps/treemap/treemap_test.go | 60 +++++++++++++++++++++++-- sets/treeset/treeset.go | 19 ++++++-- sets/treeset/treeset_test.go | 55 ++++++++++++++++++++--- trees/redblacktree/redblacktree_test.go | 34 +++++++++++--- 5 files changed, 158 insertions(+), 19 deletions(-) diff --git a/maps/treemap/treemap.go b/maps/treemap/treemap.go index efa46e43..f1640bfd 100644 --- a/maps/treemap/treemap.go +++ b/maps/treemap/treemap.go @@ -43,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 @@ -145,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 66f411c4..ac4d778b 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -311,7 +311,25 @@ 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) @@ -346,11 +364,45 @@ func TestMapIterator(t *testing.T) { 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/treeset/treeset.go b/sets/treeset/treeset.go index a1b8ee93..3a0de080 100644 --- a/sets/treeset/treeset.go +++ b/sets/treeset/treeset.go @@ -35,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 @@ -110,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 31428ac8..ccdb16c4 100644 --- a/sets/treeset/treeset_test.go +++ b/sets/treeset/treeset_test.go @@ -192,10 +192,25 @@ 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() { @@ -225,11 +240,41 @@ func TestSetIterator(t *testing.T) { 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/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 377ee9e2..3f5987a3 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -407,7 +407,7 @@ func TestRedBlackTreeIterator3Prev(t *testing.T) { } } -func TestRedBlackTreeIterator4(t *testing.T) { +func TestRedBlackTreeIterator4Next(t *testing.T) { tree := NewWithIntComparator() tree.Put(13, 5) tree.Put(8, 3) @@ -419,7 +419,6 @@ func TestRedBlackTreeIterator4(t *testing.T) { tree.Put(6, 2) tree.Put(22, 8) tree.Put(27, 10) - // │ ┌── 27 // │ ┌── 25 // │ │ └── 22 @@ -430,10 +429,7 @@ func TestRedBlackTreeIterator4(t *testing.T) { // └── 8 // │ ┌── 6 // └── 1 - it := tree.Iterator() - - // Iterator (next) count := 0 for it.Next() { count++ @@ -452,8 +448,34 @@ func TestRedBlackTreeIterator4(t *testing.T) { if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue { t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue) } +} - // Iterator (prev) +func TestRedBlackTreeIterator4(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 := tree.Size() + for it.Next() { + } for it.Prev() { count-- value := it.Value()