Skip to content

Commit

Permalink
Merge pull request #18 from emirpasic/reverse_iterator
Browse files Browse the repository at this point in the history
Reverse iterator
  • Loading branch information
emirpasic authored Jun 25, 2016
2 parents 2ccfba5 + eb4bb22 commit d5a7c62
Show file tree
Hide file tree
Showing 32 changed files with 886 additions and 152 deletions.
53 changes: 41 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -53,17 +55,18 @@ Containers are either ordered or unordered. All ordered containers provide [stat

| Container | Ordered | [Iterator](#iterator) | [Enumerable](#enumerable) | Ordered by |
| :--- | :---: | :---: | :---: | :---: |
| [ArrayList](#arraylist) | yes | yes | yes | index |
| [ArrayList](#arraylist) | yes | yes* | yes | index |
| [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index |
| [DoublyLinkedList](#doublylinkedlist) | yes | yes | yes | index |
| [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index |
| [HashSet](#hashset) | no | no | no | index |
| [TreeSet](#treeset) | yes | yes | yes | index |
| [TreeSet](#treeset) | yes | yes* | yes | index |
| [LinkedListStack](#linkedliststack) | yes | yes | no | index |
| [ArrayStack](#arraystack) | yes | yes | no | index |
| [ArrayStack](#arraystack) | yes | yes* | no | index |
| [HashMap](#hashmap) | no | no | no | key |
| [TreeMap](#treemap) | yes | yes | yes | key |
| [RedBlackTree](#redblacktree) | yes | yes | no | key |
| [BinaryHeap](#binaryheap) | yes | yes | no | index |
| [TreeMap](#treemap) | yes | yes* | yes | key |
| [RedBlackTree](#redblacktree) | yes | yes* | no | key |
| [BinaryHeap](#binaryheap) | yes | yes* | no | index |
| | | <sub><sup>*reversible</sup></sub> | | |

### Lists

Expand Down Expand Up @@ -572,12 +575,12 @@ Some data structures (e.g. TreeMap, TreeSet) require a comparator function to au

Comparator is defined as:

Return values:
Return values (int):

```go
-1, if a < b
0, if a == b
1, if a > b
negative , if a < b
zero , if a == b
positive , if a > b
```

Comparator signature:
Expand Down Expand Up @@ -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

Expand All @@ -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.
Expand Down
9 changes: 8 additions & 1 deletion containers/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// Package containers provides core interfaces and functions for data structures.
//
// Container is the base interface for all data structures to implement.
//
// Iterators provide stateful iterators.
//
// Enumerable provides Ruby inspired (each, select, map, find, any?, etc.) container functions.
package containers

import "github.com/emirpasic/gods/utils"

// Container is base interface that all data structures implement
// Container is base interface that all data structures implement.
type Container interface {
Empty() bool
Size() int
Expand Down
3 changes: 0 additions & 3 deletions containers/enumerable.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
32 changes: 30 additions & 2 deletions containers/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -55,3 +53,33 @@ type IteratorWithKey interface {
// Does not modify the state of the iterator.
Key() interface{}
}

// ReverseIteratorWithIndex is stateful iterator for ordered containers whose values can be fetched by an index.
//
// Essentially it is the same as IteratorWithIndex, but provides additional Prev() function to enable traversal in reverse.
type ReverseIteratorWithIndex interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
Prev() bool

IteratorWithIndex
// Next() bool
// Value() interface{}
// Index() int
}

// ReverseIteratorWithKey is a stateful iterator for ordered containers whose elements are key value pairs.
//
// Essentially it is the same as IteratorWithKey, but provides additional Prev() function to enable traversal in reverse.
type ReverseIteratorWithKey interface {
// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Key() and Value().
// Modifies the state of the iterator.
Prev() bool

IteratorWithKey
// Next() bool
// Value() interface{}
// Key() interface{}
}
23 changes: 18 additions & 5 deletions lists/arraylist/arraylist.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -41,7 +42,7 @@ import (
func assertInterfaceImplementation() {
var _ lists.List = (*List)(nil)
var _ containers.EnumerableWithIndex = (*List)(nil)
var _ containers.IteratorWithIndex = (*Iterator)(nil)
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
}

// List holds the elements in a slice
Expand Down Expand Up @@ -194,7 +195,19 @@ func (list *List) Iterator() Iterator {
// If Next() returns true, then next element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Next() bool {
iterator.index++
if iterator.index < iterator.list.size {
iterator.index++
}
return iterator.list.withinRange(iterator.index)
}

// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value().
// Modifies the state of the iterator.
func (iterator *Iterator) Prev() bool {
if iterator.index >= 0 {
iterator.index--
}
return iterator.list.withinRange(iterator.index)
}

Expand Down
57 changes: 53 additions & 4 deletions lists/arraylist/arraylist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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()
Expand Down
34 changes: 28 additions & 6 deletions lists/doublylinkedlist/doublylinkedlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -41,7 +42,7 @@ import (
func assertInterfaceImplementation() {
var _ lists.List = (*List)(nil)
var _ containers.EnumerableWithIndex = (*List)(nil)
var _ containers.IteratorWithIndex = (*Iterator)(nil)
var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil)
}

// List holds the elements, where each element points to the next and previous element
Expand Down Expand Up @@ -315,19 +316,40 @@ 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
}
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{} {
Expand Down
Loading

0 comments on commit d5a7c62

Please sign in to comment.