diff --git a/README.md b/README.md index 443c37d..deed77b 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ func main() { ####Lists -A list is a data structure that can store elements and may have repeated values. There is no ordering in a list. The user can access and remove an element by the index position. +A list is a data structure that can store values and may have repeated values. There is no ordering in a list. The user can access and remove a value by the index position. All lists implement the list interface with the following methods: @@ -134,10 +134,11 @@ All lists implement the list interface with the following methods: type Interface interface { Get(index int) (interface{}, bool) Remove(index int) - Add(elements ...interface{}) - Contains(elements ...interface{}) bool + Add(values ...interface{}) + Contains(values ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) + Insert(index int, values ...interface{}) containers.Interface // Empty() bool @@ -180,12 +181,14 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` #####SinglyLinkedList -This structure implements the _List_ interface and is a linked data structure where each element points to the next in the list. +This structure implements the _List_ interface and is a linked data structure where each value points to the next in the list. Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. @@ -215,12 +218,14 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` #####DoublyLinkedList -This structure implements the _List_ interface and is a linked data structure where each element points to the next and previous element in the list. +This structure implements the _List_ interface and is a linked data structure where each value points to the next and previous element in the list. Direct access method _Get(index)_ and _Remove()_ are of linear performance. _Append_ and _Prepend_ are of constant time performance. Checking with _Contains()_ is of quadratic complexity. @@ -250,6 +255,8 @@ func main() { _ = list.Size() // 0 list.Add("a") // ["a"] list.Clear() // [] + list.Insert(0, "b") // ["b"] + list.Insert(0, "a") // ["a","b"] } ``` diff --git a/lists/arraylist/arraylist.go b/lists/arraylist/arraylist.go index f98b5e5..278f153 100644 --- a/lists/arraylist/arraylist.go +++ b/lists/arraylist/arraylist.go @@ -57,10 +57,10 @@ func New() *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 +func (list *List) Add(values ...interface{}) { + list.growBy(len(values)) + for _, value := range values { + list.elements[list.size] = value list.size += 1 } } @@ -94,12 +94,12 @@ func (list *List) Remove(index int) { // 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 { +func (list *List) Contains(values ...interface{}) bool { - for _, searchElement := range elements { + for _, searchValue := range values { found := false for _, element := range list.elements { - if element == searchElement { + if element == searchValue { found = true break } @@ -142,13 +142,39 @@ func (list *List) Sort(comparator utils.Comparator) { utils.Sort(list.elements[:list.size], comparator) } -// Swaps values of two elements at the given indices. +// Swaps the two values at the specified positions. func (list *List) Swap(i, j int) { if list.withinRange(i) && list.withinRange(j) { list.elements[i], list.elements[j] = list.elements[j], list.elements[i] } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, values ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(values...) + } + return + } + + l := len(values) + list.growBy(l) + list.size += l + // Shift old to right + for i := list.size - 1; i >= index+l; i-- { + list.elements[i] = list.elements[i-l] + } + // Insert new + for i, value := range values { + list.elements[index+i] = value + } +} + func (list *List) String() string { str := "ArrayList\n" values := []string{} @@ -161,7 +187,7 @@ func (list *List) String() string { // 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 + return index >= 0 && index < list.size } func (list *List) resize(cap int) { diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go index 4eb239f..ab07f67 100644 --- a/lists/arraylist/arraylist_test.go +++ b/lists/arraylist/arraylist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package arraylist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -120,6 +121,19 @@ func TestArrayList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkArrayList(b *testing.B) { diff --git a/lists/doublylinkedlist/doublylinkedlist.go b/lists/doublylinkedlist/doublylinkedlist.go index ed40eeb..b679797 100644 --- a/lists/doublylinkedlist/doublylinkedlist.go +++ b/lists/doublylinkedlist/doublylinkedlist.go @@ -244,6 +244,60 @@ func (list *List) Swap(i, j int) { } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, values ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(values...) + } + fmt.Println(list.Values()) + return + } + + list.size += len(values) + + var beforeElement *element + var foundElement *element + // determine traversal direction, last to first or first to last + if list.size-index < index { + foundElement = list.last + for e := list.size - 1; e != index; e, foundElement = e-1, foundElement.prev { + beforeElement = foundElement.prev + } + } else { + foundElement = list.first + for e := 0; e != index; e, foundElement = e+1, foundElement.next { + beforeElement = foundElement + } + } + + if foundElement == list.first { + oldNextElement := list.first + for i, value := range values { + newElement := &element{value: value} + if i == 0 { + list.first = newElement + } else { + beforeElement.next = newElement + } + beforeElement = newElement + } + beforeElement.next = oldNextElement + } else { + oldNextElement := beforeElement.next + for _, value := range values { + newElement := &element{value: value} + beforeElement.next = newElement + beforeElement = newElement + } + beforeElement.next = oldNextElement + } +} + func (list *List) String() string { str := "DoublyLinkedList\n" values := []string{} @@ -256,5 +310,5 @@ func (list *List) String() string { // 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 + return index >= 0 && index < list.size } diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go index 0c78c7b..528b00f 100644 --- a/lists/doublylinkedlist/doublylinkedlist_test.go +++ b/lists/doublylinkedlist/doublylinkedlist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package doublylinkedlist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -122,6 +123,19 @@ func TestDoublyLinkedList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkDoublyLinkedList(b *testing.B) { diff --git a/lists/lists.go b/lists/lists.go index 7e03285..5a83a4c 100644 --- a/lists/lists.go +++ b/lists/lists.go @@ -26,10 +26,11 @@ import ( type Interface interface { Get(index int) (interface{}, bool) Remove(index int) - Add(elements ...interface{}) - Contains(elements ...interface{}) bool + Add(values ...interface{}) + Contains(values ...interface{}) bool Sort(comparator utils.Comparator) Swap(index1, index2 int) + Insert(index int, values ...interface{}) containers.Interface // Empty() bool diff --git a/lists/singlylinkedlist/singlylinkedlist.go b/lists/singlylinkedlist/singlylinkedlist.go index a9b4d63..e4730ae 100644 --- a/lists/singlylinkedlist/singlylinkedlist.go +++ b/lists/singlylinkedlist/singlylinkedlist.go @@ -223,6 +223,51 @@ func (list *List) Swap(i, j int) { } } +// Inserts values at specified index position shifting the value at that position (if any) and any subsequent elements to the right. +// Does not do anything if position is negative or bigger than list's size +// Note: position equal to list's size is valid, i.e. append. +func (list *List) Insert(index int, values ...interface{}) { + + if !list.withinRange(index) { + // Append + if index == list.size { + list.Add(values...) + } + fmt.Println(list.Values()) + return + } + + list.size += len(values) + + var beforeElement *element + foundElement := list.first + for e := 0; e != index; e, foundElement = e+1, foundElement.next { + beforeElement = foundElement + } + + if foundElement == list.first { + oldNextElement := list.first + for i, value := range values { + newElement := &element{value: value} + if i == 0 { + list.first = newElement + } else { + beforeElement.next = newElement + } + beforeElement = newElement + } + beforeElement.next = oldNextElement + } else { + oldNextElement := beforeElement.next + for _, value := range values { + newElement := &element{value: value} + beforeElement.next = newElement + beforeElement = newElement + } + beforeElement.next = oldNextElement + } +} + func (list *List) String() string { str := "SinglyLinkedList\n" values := []string{} @@ -235,5 +280,5 @@ func (list *List) String() string { // 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 + return index >= 0 && index < list.size } diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go index 4956507..df08466 100644 --- a/lists/singlylinkedlist/singlylinkedlist_test.go +++ b/lists/singlylinkedlist/singlylinkedlist_test.go @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package singlylinkedlist import ( + "fmt" "github.com/emirpasic/gods/utils" "testing" ) @@ -122,6 +123,19 @@ func TestSinglyLinkedList(t *testing.T) { t.Errorf("Got %v expected %v", actualValue, true) } + list.Insert(0, "h") + list.Insert(0, "e") + list.Insert(1, "f") + list.Insert(2, "g") + list.Insert(4, "i") + list.Insert(0, "a", "b") + list.Insert(list.Size(), "j", "k") + list.Insert(2, "c", "d") + + if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s%s%s%s%s", list.Values()...), "abcdefghijk"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } func BenchmarkSinglyLinkedList(b *testing.B) {