Skip to content

Commit

Permalink
Merge pull request #10 from architagr/implement_list
Browse files Browse the repository at this point in the history
add single linked list
  • Loading branch information
architagr authored Mar 10, 2024
2 parents 51dc160 + 4f91ae3 commit bc2826a
Show file tree
Hide file tree
Showing 7 changed files with 666 additions and 3 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ We have also done some basic benchmarking with some of the most commonly used pa
### implemented collections:

- [Stack (using linked list)](stack/README.md)
- [Queue (using linked list)](queue/README.md)
- [Queue (using linked list)](queue/README.md)
- [Single linked list](list/singleLinkedList_README)
49 changes: 49 additions & 0 deletions list/list_contract.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package list

type IDeepCopy interface {
Copy() interface{}
Equal(val interface{}) bool
}

type IList[T IDeepCopy] interface {
// Add adds data to the end of the list
Add(data *T) (resultIndex int)
// AddAtIndex adds data to the index in the list and shifts all data to right
// if the index is out of bound then return error
AddAtIndex(index int, data *T) (err error)
// Remove removes data from the list and returns error if the data is not found
Remove(data *T) (removedIndex int, err error)
// RemoveAtIndex removes data at the index, if the index is not valid then returns error
RemoveAtIndex(index int) (data *T, err error)
// Count return the count of elements in the list
Count() int
// Get gets data at the index, if index is not valid then it returns error
Get(index int) (data *T, err error)
// Set updates the data at the index, if index is not valid then returns error
Set(index int, data *T) error
// Find helps to get the first occourance if the data that matches according to the filter func and also returns index
// if index is -1 then the data is not found
Find(f filterfunc[T]) (index int)
}

type filterfunc[T IDeepCopy] func(data *T) bool

type IItratorList[T IDeepCopy] interface {
IList[T]
// Filter helps to get the all data that matches according to the filter func and also returns index
Filter(f filterfunc[T]) []T
// DeepCopy this is used to create a copy of the list
DeepCopy() []T
}

type IIndexedItratorList[T IDeepCopy] interface {
IItratorList[T]
// FindByIndexedKey get the first occourance if the data that matches according to the filter func and also returns index,
// this helps in fast search ad it will do a binary search on the indexKey
// this is similar to Non-Clustered Index in database
FindByIndexedKey(indexKey string, key string) (data T, index int)
// FindByIndexedKey get the first occourance if the data that matches according to the filter func and also returns index,
// this helps in fast search ad it will do a binary search on the indexKey
// this is similar to Non-Clustered Index in database
FilterByIndexedKey(indexKey string, key string) []T
}
107 changes: 107 additions & 0 deletions list/singleLinkedList_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Single List list

This package implements generic Single linked list, the data of the list should implement the `IDeepCopy` interface.

## Quick Start
```go
package main

import (
"github.com/architagr/golang_collections/list"
)


type Integer int

func InitInteger(val int) Integer {
return Integer(val)
}
func (obj Integer) Copy() interface{} {
return obj
}

func (obj Integer) Equal(val interface{}) bool {
x := val.(Integer)
return int(x) == int(obj)
}

func main() {
linkedList := InitSingleLinkedList[Integer]()
intVal := InitInteger(0)
linkedList.Add(&intVal)
intVal2 := InitInteger(1)
err := obj.AddAtIndex(0, &intVal2)
if err != nil{
panic(fmt.Errorf("Error in adding at 0th index: %s", err.Error()))
}
data, err := linkedList.Get(0)
if err != nil{
panic(fmt.Errorf("Error in getting value at a index: %s", err.Error()))
}
intVal3 := InitInteger(2)
err := linkedList.Set(0, &intVal3)
if err != nil {
panic(fmt.Errorf("Error in setting value at a index: %s", err.Error()))
}
index, err := linkedList.Remove(&intVal2)
if err != nil {
panic(fmt.Errorf("error when removing a node: %s", err.Error()))
}

data, err := linkedList.RemoveAtIndex(1)
if err != nil {
panic(fmt.Errorf("error when removing a node at a index: %s", err.Error()))
}

index := obj.Find(func(val *Integer) bool {
x := InitInteger(2)
return val.Equal(x)
})
if index == -1 {
panic(fmt.Errorf("error when finding value: %s", err.Error()))
}

}
```
## Functions available

the package exposes below listed functions

### InitSingleLinkedList[T IDeepCopy]

created a new single linked list that can have nodes that can hold data of type `IDeepCopy`.
T can be of any data type that implements `IDeepCopy`.

### Method in the object of single linked list
#### Add(data *T) (resultIndex int)

this is a function adds data to the end of the list.

#### AddAtIndex(index int, data *T) (err error)

this function adds data to the index in the list and shifts all data to right if the index is out of bound then return error.

#### Remove(data *T) (removedIndex int, err error)

This function removes data from the list and returns error if the data is not found.

#### RemoveAtIndex(index int) (data *T, err error)

This function removes data at the index, if the index is not valid then returns error.

#### Count() int

This function return the count of elements in the list.

#### Get(index int) (data *T, err error)

This function gets data at the index, if index is not valid then it returns error.

#### Set(index int, data *T) error

This function updates the data at the index, if index is not valid then returns error

#### Find(f filterfunc[T]) (index int)

This function helps to get the first occourance if the data that matches according to the filter func and also returns index, if index is -1 then the data is not found

148 changes: 148 additions & 0 deletions list/single_linked_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package list

import "fmt"

func InitSingleLinkedList[T IDeepCopy]() IList[T] {
return &singleLinkedList[T]{
head: nil,
tail: nil,
indexMap: make(map[int]*singleLinkedListNode[T]),
}
}

type singleLinkedListNode[T IDeepCopy] struct {
data *T
next *singleLinkedListNode[T]
}

func initSingleLinkedListNode[T IDeepCopy](data *T) *singleLinkedListNode[T] {
return &singleLinkedListNode[T]{
data: data,
next: nil,
}
}

type singleLinkedList[T IDeepCopy] struct {
head, tail *singleLinkedListNode[T]
indexMap map[int]*singleLinkedListNode[T]
}

func (l *singleLinkedList[T]) Add(data *T) (resultIndex int) {
newNode := initSingleLinkedListNode(data)
if l.head == nil {
l.head = newNode
l.tail = newNode
} else {
l.tail.next = newNode
l.tail = newNode
}
l.indexMap[l.Count()] = newNode
return l.Count()
}

func (l *singleLinkedList[T]) AddAtIndex(index int, data *T) (err error) {
err = l.validateIndex(index)
if err != nil {
return
}

newNode := initSingleLinkedListNode(data)

for i := l.Count() - 1; i >= index; i-- {
l.indexMap[i+1] = l.indexMap[i]
}
l.indexMap[index] = newNode

if index == 0 {
newNode.next = l.head
l.head = newNode
} else {
newNode.next = l.indexMap[index+1]
l.indexMap[index-1].next = newNode
}

return
}

func (l *singleLinkedList[T]) Remove(data *T) (removedIndex int, err error) {
temp := l.head
removedIndex = 0
for temp != nil {
if (*data).Equal(*temp.data) {
_, err = l.RemoveAtIndex(removedIndex)
break
}
removedIndex++
temp = temp.next
}
if removedIndex == l.Count() {
err = fmt.Errorf("data not found")
removedIndex = -1
}
return
}
func (l *singleLinkedList[T]) RemoveAtIndex(index int) (data *T, err error) {
err = l.validateIndex(index)
if err != nil {
return
}

if index == 0 {
l.head = l.head.next
} else if index+1 == l.Count() {
l.indexMap[index-1].next = nil
l.tail = l.indexMap[index-1]
} else {
l.indexMap[index-1].next = l.indexMap[index+1]
}

initialCount := l.Count()
data = l.indexMap[index].data
delete(l.indexMap, index)
for i := index; i < initialCount-1; i++ {
l.indexMap[i] = l.indexMap[i+1]
}
delete(l.indexMap, initialCount-1)
return
}
func (l *singleLinkedList[T]) Count() int {
return len(l.indexMap)
}
func (l *singleLinkedList[T]) validateIndex(index int) error {
if index < 0 || index >= l.Count() {
return fmt.Errorf("invalid index")
}
return nil
}
func (l *singleLinkedList[T]) Get(index int) (data *T, err error) {
err = l.validateIndex(index)
if err != nil {
return
}
return l.indexMap[index].data, nil
}
func (l *singleLinkedList[T]) Set(index int, data *T) error {
err := l.validateIndex(index)
if err != nil {
return err
}
node := l.indexMap[index]
node.data = data
return nil
}

func (l *singleLinkedList[T]) Find(f filterfunc[T]) (index int) {
temp := l.head
index = 0
for temp != nil {
if f(temp.data) {
break
}
index++
temp = temp.next
}
if index == l.Count() {
index = -1
}
return
}
Loading

0 comments on commit bc2826a

Please sign in to comment.