-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from architagr/implement_list
add single linked list
- Loading branch information
Showing
7 changed files
with
666 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.