diff --git a/README.md b/README.md index 4c6006b..2cf8d6e 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 91ca046..6e73dea 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 fd2d4d4..c1a7c54 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 ad0fc09..c08d928 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 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 3f97647..cb7bdfc 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 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 539d14e..b3d9b9a 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 953ab8b..f65f728 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 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/maps.go b/maps/maps.go index 809f138..93f8bc0 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 af4aa22..b0ae988 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 749bd3f..a580d36 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 069a880..2b235c1 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 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