ArrayList addition (inc. test, example and documentation)

pull/1/head
emirpasic 9 years ago
parent a2f7d2482e
commit 3aa0eeddfb

@ -9,6 +9,8 @@ Implementation of various data structures in Go.
- [Sets](#sets)
- [HashSet](#hashset)
- [TreeSet](#treeset)
- [Lists](#lists)
- [ArrayList](#arraylist)
- [Stacks](#stacks)
- [LinkedListStack](#linkedliststack)
- [ArrayStack](#arraystack)
@ -95,6 +97,41 @@ func main() {
```
###Lists
####ArrayList
```go
package main
import "github.com/emirpasic/gods/lists/arraylist"
func main() {
list := arraylist.New()
list.Add("a") // ["a"]
list.Add("b", "c") // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") //true
_ = list.Contains("a", "b", "c", "d") //false
list.Remove(2) // ["a","b"]
list.Remove(1) // ["a"]
list.Remove(0) // []
list.Remove(0) // [] (ignored)
_ = list.Empty() // true
_ = list.Size() // 0
list.Add("a") // ["a"]
list.Clear() // []
}
```
###Stacks
The stack interface represents a last-in-first-out (LIFO) collection of objects. The usual push and pop operations are provided, as well as a method to peek at the top item on the stack, a method to check whether the stack is empty and the size (number of elements).
@ -457,6 +494,4 @@ For direct contributions, branch of from master and do _pull request_.
## License
Copyright (c) Emir Pasic , All rights reserved.
This library is distributed under the BSD-style license found in the [LICENSE](https://github.com/emirpasic/gods/blob/master/LICENSE) file.

@ -0,0 +1,47 @@
/*
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 examples
import "github.com/emirpasic/gods/lists/arraylist"
func ArrayListExample() {
list := arraylist.New()
list.Add("a") // ["a"]
list.Add("b", "c") // ["a","b","c"]
_, _ = list.Get(0) // "a",true
_, _ = list.Get(100) // nil,false
_ = list.Contains("a", "b", "c") // true
_ = list.Contains("a", "b", "c", "d") // false
list.Remove(2) // ["a","b"]
list.Remove(1) // ["a"]
list.Remove(0) // []
list.Remove(0) // [] (ignored)
_ = list.Empty() // true
_ = list.Size() // 0
list.Add("a") // ["a"]
list.Clear() // []
}

@ -28,7 +28,7 @@ package examples
import "github.com/emirpasic/gods/stacks/arraystack"
func arraystackExample() {
func ArrayStackExample() {
stack := arraystack.New() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2

@ -53,7 +53,7 @@ func byID(a, b interface{}) int {
}
}
func exampleCustomComparator() {
func CustomComparatorExample() {
set := treeset.NewWith(byID)
set.Add(User{2, "Second"})

@ -28,7 +28,7 @@ package examples
import "github.com/emirpasic/gods/maps/hashmap"
func hashmapExample() {
func HashMapExample() {
m := hashmap.New() // empty
m.Put(1, "x") // 1->x
m.Put(2, "b") // 2->b, 1->x (random order)

@ -28,7 +28,7 @@ package examples
import "github.com/emirpasic/gods/sets/hashset"
func hashsetExample() {
func HashSetExample() {
set := hashset.New() // empty (keys are of type int)
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 3, 1, 2, 4, 5 (random order, duplicates ignored)

@ -28,7 +28,7 @@ package examples
import lls "github.com/emirpasic/gods/stacks/linkedliststack"
func linkedliststackExample() {
func LinkedListStackExample() {
stack := lls.New() // empty
stack.Push(1) // 1
stack.Push(2) // 1, 2

@ -31,7 +31,7 @@ import (
rbt "github.com/emirpasic/gods/trees/redblacktree"
)
func redblacktreeExample() {
func RedBlacTtreeExample() {
tree := rbt.NewWithIntComparator() // empty(keys are of type int)
tree.Put(1, "x") // 1->x

@ -28,7 +28,7 @@ package examples
import "github.com/emirpasic/gods/maps/treemap"
func treemapExample() {
func TreeMapExample() {
m := treemap.NewWithIntComparator() // empty (keys are of type int)
m.Put(1, "x") // 1->x
m.Put(2, "b") // 1->x, 2->b (in order)

@ -28,7 +28,7 @@ package examples
import "github.com/emirpasic/gods/sets/treeset"
func treesetExample() {
func TreeSetExample() {
set := treeset.NewWithIntComparator() // empty
set.Add(1) // 1
set.Add(2, 2, 3, 4, 5) // 1, 2, 3, 4, 5 (in order, duplicates ignored)

@ -0,0 +1,182 @@
/*
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.
*/
// Implementation of list using a slice.
// Structure is not thread safe.
// References: http://en.wikipedia.org/wiki/List_%28abstract_data_type%29
package arraylist
import (
"fmt"
"github.com/emirpasic/gods/lists"
"strings"
)
func assertInterfaceImplementation() {
var _ lists.Interface = (*List)(nil)
}
type List struct {
elements []interface{}
size int
}
const (
GROWTH_FACTOR = float32(1.5) // growth by 50%
SHRINK_FACTOR = float32(0.5) // shrink when size is 50% of capacity (0 means never shrink)
)
// Instantiates a new empty list
func New() *List {
return &List{}
}
// Appends a value at the end of the list
func (list *List) Add(elements ...interface{}) {
list.growBy(len(elements))
for _, element := range elements {
list.elements[list.size] = element
list.size += 1
}
}
// Returns the element at index.
// Second return parameter is true if index is within bounds of the array and array is not empty, otherwise false.
func (list *List) Get(index int) (interface{}, bool) {
if !list.withinRange(index) {
return nil, false
}
return list.elements[index], true
}
// Removes one or more elements from the list with the supplied indices.
func (list *List) Remove(index int) {
if !list.withinRange(index) {
return
}
list.elements[index] = nil // cleanup reference
copy(list.elements[index:], list.elements[index+1:list.size]) // shift to the left by one (slow operation, need ways to optimize this)
list.size -= 1
list.shrink()
}
// Check if elements (one or more) are present in the set.
// All elements have to be present in the set for the method to return true.
// Performance time complexity of n^2.
// Returns true if no arguments are passed at all, i.e. set is always super-set of empty set.
func (list *List) Contains(elements ...interface{}) bool {
for _, searchElement := range elements {
found := false
for _, element := range list.elements {
if element == searchElement {
found = true
break
}
}
if !found {
return false
}
}
return true
}
// Returns all elements in the list.
func (list *List) Values() []interface{} {
newElements := make([]interface{}, list.size, list.size)
copy(newElements, list.elements[:list.size])
return newElements
}
// Returns true if list does not contain any elements.
func (list *List) Empty() bool {
return list.size == 0
}
// Returns number of elements within the list.
func (list *List) Size() int {
return list.size
}
// Removes all elements from the list.
func (list *List) Clear() {
list.size = 0
list.elements = []interface{}{}
}
func (list *List) String() string {
str := "ArrayList\n"
values := []string{}
for _, value := range list.elements {
values = append(values, fmt.Sprintf("%v", value))
}
str += strings.Join(values, ", ")
return str
}
/*************
* Internals *
*************/
// Check that the index is withing bounds of the list
func (list *List) withinRange(index int) bool {
return index >= 0 && index < list.size && list.size != 0
}
func (list *List) resize(cap int) {
newElements := make([]interface{}, cap, cap)
copy(newElements, list.elements)
list.elements = newElements
}
// Expand the array if necessary, i.e. capacity will be reached if we add n elements
func (list *List) growBy(n int) {
// Grow when capacity is reached by a factor of 1.5 and add number of elements
currentCapacity := cap(list.elements)
if list.size+n >= currentCapacity {
newCapacity := int(GROWTH_FACTOR * float32(currentCapacity+n))
list.resize(newCapacity)
}
}
// Shrink the array if necessary, i.e. when size is SHRINK_FACTOR percent of current capacity
func (list *List) shrink() {
if SHRINK_FACTOR == 0.0 {
return
}
// Shrink when size is at SHRINK_FACTOR * capacity
currentCapacity := cap(list.elements)
if list.size <= int(float32(currentCapacity)*SHRINK_FACTOR) {
list.resize(list.size)
}
}

@ -0,0 +1,117 @@
/*
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 arraylist
import (
"testing"
)
func TestArrayList(t *testing.T) {
list := New()
list.Add("a", "b", "c", "d", "e", "f", "g")
list.Clear()
if actualValue := list.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
list.Add("a")
list.Add("b", "c")
if actualValue := list.Empty(); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue := list.Size(); actualValue != 3 {
t.Errorf("Got %v expected %v", actualValue, 3)
}
if actualValue, ok := list.Get(2); actualValue != "c" || !ok {
t.Errorf("Got %v expected %v", actualValue, "c")
}
list.Remove(2)
if actualValue, ok := list.Get(2); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, nil)
}
list.Remove(1)
list.Remove(0)
if actualValue := list.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Size(); actualValue != 0 {
t.Errorf("Got %v expected %v", actualValue, 0)
}
list.Add("a", "b", "c")
if actualValue := list.Contains("a", "b", "c"); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
if actualValue := list.Contains("a", "b", "c", "d"); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
list.Clear()
if actualValue := list.Contains("a"); actualValue != false {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue, ok := list.Get(0); actualValue != nil || ok {
t.Errorf("Got %v expected %v", actualValue, false)
}
if actualValue := list.Empty(); actualValue != true {
t.Errorf("Got %v expected %v", actualValue, true)
}
}
func BenchmarkArrayList(b *testing.B) {
for i := 0; i < b.N; i++ {
list := New()
for n := 0; n < 1000; n++ {
list.Add(i)
}
for !list.Empty() {
list.Remove(0)
}
}
}

@ -0,0 +1,30 @@
/*
Copyright (c) Emir Pasic, All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. See the file LICENSE included
with this distribution for more information.
*/
package lists
type Interface interface {
Get(index int) (interface{}, bool)
Remove(index int)
Add(elements ...interface{})
Contains(elements ...interface{}) bool
Empty() bool
Size() int
Clear()
Values() []interface{}
}

@ -177,3 +177,15 @@ func sameElements(a []interface{}, b []interface{}) bool {
}
return true
}
func BenchmarkHashMap(b *testing.B) {
for i := 0; i < b.N; i++ {
m := New()
for n := 0; n < 1000; n++ {
m.Put(n, n)
}
for n := 0; n < 1000; n++ {
m.Remove(n)
}
}
}

@ -159,3 +159,15 @@ func TestTreeMap(t *testing.T) {
}
}
func BenchmarkTreeMap(b *testing.B) {
for i := 0; i < b.N; i++ {
m := NewWithIntComparator()
for n := 0; n < 1000; n++ {
m.Put(n, n)
}
for n := 0; n < 1000; n++ {
m.Remove(n)
}
}
}

@ -65,7 +65,7 @@ func (set *Set) Remove(items ...interface{}) {
}
}
// Check wether items (one or more) are present in the set.
// Check if items (one or more) are present in the set.
// All items have to be present in the set for the method to return true.
// Returns true if no arguments are passed at all, i.e. set is always superset of empty set.
func (set *Set) Contains(items ...interface{}) bool {

@ -89,3 +89,15 @@ func TestHashSet(t *testing.T) {
}
}
func BenchmarkHashSet(b *testing.B) {
for i := 0; i < b.N; i++ {
set := New()
for n := 0; n < 1000; n++ {
set.Add(i)
}
for n := 0; n < 1000; n++ {
set.Remove(n)
}
}
}

@ -19,9 +19,9 @@ with this distribution for more information.
package sets
type Interface interface {
Add(items ...interface{})
Remove(items ...interface{})
Contains(items ...interface{}) bool
Add(elements ...interface{})
Remove(elements ...interface{})
Contains(elements ...interface{}) bool
Empty() bool
Size() int
Clear()

@ -84,3 +84,15 @@ func TestTreeSet(t *testing.T) {
}
}
func BenchmarkTreeSet(b *testing.B) {
for i := 0; i < b.N; i++ {
set := NewWithIntComparator()
for n := 0; n < 1000; n++ {
set.Add(i)
}
for n := 0; n < 1000; n++ {
set.Remove(n)
}
}
}

@ -41,8 +41,8 @@ func assertInterfaceImplementation() {
}
type Stack struct {
items []interface{}
top int
elements []interface{}
top int
}
// Instantiates a new empty stack
@ -53,24 +53,23 @@ func New() *Stack {
// Pushes a value onto the top of the stack
func (stack *Stack) Push(value interface{}) {
// Increase when capacity is reached by a factor of 1.5 and add one so it grows when size is zero
if stack.top+1 >= cap(stack.items) {
currentSize := len(stack.items)
if stack.top+1 >= cap(stack.elements) {
currentSize := len(stack.elements)
sizeIncrease := int(1.5*float32(currentSize) + 1.0)
newSize := currentSize + sizeIncrease
newItems := make([]interface{}, newSize, newSize)
copy(newItems, stack.items)
stack.items = newItems
copy(newItems, stack.elements)
stack.elements = newItems
}
stack.top += 1
stack.items[stack.top] = value
stack.elements[stack.top] = value
}
// Pops (removes) top element on stack and returns it, or nil if stack is empty.
// Second return parameter is true, unless the stack was empty and there was nothing to pop.
func (stack *Stack) Pop() (value interface{}, ok bool) {
if stack.top >= 0 {
value, ok = stack.items[stack.top], true
// TODO shrink slice at some point
value, ok = stack.elements[stack.top], true
stack.top -= 1
return
}
@ -81,7 +80,7 @@ func (stack *Stack) Pop() (value interface{}, ok bool) {
// Second return parameter is true, unless the stack was empty and there was nothing to peek.
func (stack *Stack) Peek() (value interface{}, ok bool) {
if stack.top >= 0 {
return stack.items[stack.top], true
return stack.elements[stack.top], true
}
return nil, false
}
@ -99,13 +98,13 @@ func (stack *Stack) Size() int {
// Removes all elements from the stack.
func (stack *Stack) Clear() {
stack.top = -1
stack.items = []interface{}{}
stack.elements = []interface{}{}
}
func (stack *Stack) String() string {
str := "ArrayStack\n"
values := []string{}
for _, value := range stack.items {
for _, value := range stack.elements {
values = append(values, fmt.Sprintf("%v", value))
}
str += strings.Join(values, ", ")

@ -80,9 +80,6 @@ func TestArrayStack(t *testing.T) {
}
func BenchmarkArrayStack(b *testing.B) {
// Faster in comparison to the LinkedListStack
// BenchmarkArrayStack 5000 325010 ns/op 71648 B/op 1009 allocs/op
// BenchmarkLinkedListStack 5000 390812 ns/op 40016 B/op 2001 allocs/op
for i := 0; i < b.N; i++ {
stack := New()
for n := 0; n < 1000; n++ {

@ -80,9 +80,6 @@ func TestLinkedListStack(t *testing.T) {
}
func BenchmarkLinkedListStack(b *testing.B) {
// Slower in comparison to the ArrayStack
// BenchmarkArrayStack 5000 325010 ns/op 71648 B/op 1009 allocs/op
// BenchmarkLinkedListStack 5000 390812 ns/op 40016 B/op 2001 allocs/op
for i := 0; i < b.N; i++ {
stack := New()
for n := 0; n < 1000; n++ {

@ -159,3 +159,15 @@ func TestRedBlackTree(t *testing.T) {
}
}
func BenchmarkRedBlackTree(b *testing.B) {
for i := 0; i < b.N; i++ {
tree := NewWithIntComparator()
for n := 0; n < 1000; n++ {
tree.Put(n, n)
}
for n := 0; n < 1000; n++ {
tree.Remove(n)
}
}
}

Loading…
Cancel
Save