Skip to content

Commit

Permalink
Merge pull request #16 from armineyvazi/feat/concurrency-search-linke…
Browse files Browse the repository at this point in the history
…dlist

feat: Added concurrency search in linkedlist
  • Loading branch information
Iajrdev authored Dec 11, 2024
2 parents 4041ecf + 0c3c24d commit 71b6daa
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 22 deletions.
58 changes: 55 additions & 3 deletions api/v2/echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package v2

import (
"context"
"fmt"
"linkedlist/linkedlist"
"log/slog"
"net/http"
Expand Down Expand Up @@ -82,6 +81,9 @@ func V2() (*echo.Echo, error) {
e.GET("/numbers/rwmutex/value/:value", s.RWMutexFind)
e.GET("/numbers/rwmutex/index/:index", s.RWMutexGet)

e.GET("/numbers/concurrency/value/:value", s.ConcurrencySearchValue)
e.GET("/numbers/concurrency/index/:index", s.SearchInSegmentedNodes)

return e, nil
}

Expand Down Expand Up @@ -129,7 +131,6 @@ func (s *server) Find(c echo.Context) error {
valueStr := c.Param("value")
value, err := strconv.Atoi(valueStr)
if err != nil {
fmt.Println(err)
return echo.NewHTTPError(echo.ErrBadRequest.Code, "Invalid value")
}

Expand Down Expand Up @@ -176,7 +177,6 @@ func (s *server) RWMutexFind(c echo.Context) error {
valueStr := c.Param("value")
value, err := strconv.Atoi(valueStr)
if err != nil {
fmt.Println(err)
return echo.NewHTTPError(echo.ErrBadRequest.Code, "Invalid value")
}

Expand All @@ -196,6 +196,58 @@ func (s *server) RWMutexFind(c echo.Context) error {
return nil
}

func (s *server) SearchInSegmentedNodes(c echo.Context) error {
valueStr := c.Param("index")
index, err := strconv.Atoi(valueStr)
if err != nil {
return echo.NewHTTPError(echo.ErrBadRequest.Code, "Invalid value")
}

ctx, cancel := context.WithCancel(c.Request().Context())
defer cancel()

s.mutex.RLock()
value, ok := s.list.SearchInSegmentedNodes(ctx, index)
s.mutex.RUnlock()

if !ok {
return echo.NewHTTPError(echo.ErrNotFound.Code, "Value not found")
}

data := ListEntity{
Index: uint(index),
Value: value,
}
c.JSON(http.StatusOK, data)
return nil
}

func (s *server) ConcurrencySearchValue(c echo.Context) error {
valueStr := c.Param("value")
value, err := strconv.Atoi(valueStr)
if err != nil {
return echo.NewHTTPError(echo.ErrBadRequest.Code, "Invalid value")
}

ctx, cancel := context.WithCancel(c.Request().Context())
defer cancel()

s.mutex.RLock()
index, ok := s.list.SearchConcurrently(ctx, cancel, value)
s.mutex.RUnlock()

if !ok {
return echo.NewHTTPError(echo.ErrNotFound.Code, "Value not found")
}

data := ListEntity{
Index: uint(index),
Value: value,
}
c.JSON(http.StatusOK, data)
return nil
}

func (s *server) RWMutexGet(c echo.Context) error {
indexStr := c.Param("index")
index, err := strconv.ParseUint(indexStr, 10, 32)
Expand Down
171 changes: 152 additions & 19 deletions linkedlist/linkedList.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package linkedlist

import (
"context"
"sync"
)

type Node struct {
Value int
Next *Node
Expand All @@ -10,15 +15,20 @@ type LinkedList struct {
length uint
}

var (
Nodes []*Node
part uint = 10
)

func NewLinkedList() *LinkedList {
return &LinkedList{}
}

func (l *LinkedList) Find(n int) (index uint, found bool) {
func (l *LinkedList) Find(val int) (index uint, found bool) {
current := l.head
index = 0
for current != nil {
if current.Value == n {
if current.Value == val {
return index, true
}
current = current.Next
Expand All @@ -27,6 +37,35 @@ func (l *LinkedList) Find(n int) (index uint, found bool) {
return 0, false
}

func (l *LinkedList) Remove(index uint) bool {
if index >= l.length {
return false
}
l.updateCacheForRemove(index)
if index == 0 {
l.head = l.head.Next
l.length--
return true
}

current := l.head
for i := uint(0); i < index-1; i++ {
if current.Next == nil {
return false
}
current = current.Next
}

if current.Next == nil {
return false
}

current.Next = current.Next.Next
l.length--

return true
}

func (l *LinkedList) Get(index uint) (int, bool) {
current := l.head
for i := uint(0); i < index; i++ {
Expand Down Expand Up @@ -54,6 +93,7 @@ func (l *LinkedList) Insert(index uint, val int) bool {
newNode.Next = l.head
l.head = newNode
l.length++
l.updateCacheForInsert(index, newNode)
return true
}

Expand All @@ -68,35 +108,52 @@ func (l *LinkedList) Insert(index uint, val int) bool {
newNode.Next = current.Next
current.Next = newNode
l.length++

l.updateCacheForInsert(index, newNode)

return true
}

func (l *LinkedList) Remove(index uint) bool {
if index >= l.length {
return false
}
func (l *LinkedList) updateCacheForRemove(index uint) {

indexNodes := int(index/part) + 1

if index == 0 {
l.head = l.head.Next
l.length--
return true
indexNodes = 0
}

current := l.head
for i := uint(0); i < index-1; i++ {
if current.Next == nil {
return false
for i := indexNodes; i < len(Nodes); i++ {
if Nodes[i].Next != nil {
Nodes[i] = Nodes[i].Next
} else {
Nodes = Nodes[:i]
}
current = current.Next

}

if current.Next == nil {
return false
}

func (l *LinkedList) updateCacheForInsert(index uint, newNode *Node) {
partIndex := int(index / part)
if partIndex >= len(Nodes) {
Nodes = append(Nodes, newNode)
return
}

current.Next = current.Next.Next
l.length--
return true
var counter = index
newNode1 := newNode
for newNode1 != nil {
if counter%part == 0 {
if partIndex >= len(Nodes) {
Nodes = append(Nodes, newNode1)
} else {
Nodes[partIndex] = newNode1
}
partIndex++
}
counter++
newNode1 = newNode1.Next
}
}

func (l *LinkedList) HandleList() []int {
Expand All @@ -108,3 +165,79 @@ func (l *LinkedList) HandleList() []int {
}
return values
}

func (l *LinkedList) SearchConcurrently(ctx context.Context, cancel context.CancelFunc, find int) (int, bool) {
var result int
var isFound bool
var mu sync.Mutex
var wg sync.WaitGroup

for i := 0; i < len(Nodes); i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
index := Nodes[i]
for j := 0; j < int(part); j++ {
select {
case <-ctx.Done():
return
default:
}

if index == nil {
return
}

if index.Value == find {
mu.Lock()
result = (i * int(part)) + j
isFound = true
mu.Unlock()
cancel()
return
}

if index.Next == nil {
return
}

select {
case <-ctx.Done():
return
default:
index = index.Next
}
}
}(i)
}

wg.Wait()
return result, isFound
}

func (l *LinkedList) SearchInSegmentedNodes(ctx context.Context, index int) (int, bool) {
indexStart := index / 10
if indexStart >= len(Nodes) {
return 0, false
}

if index == 0 && len(Nodes) != 0 && Nodes[0].Value >= 0 {
return Nodes[0].Value, true
}

nodes := Nodes[indexStart]
targetIndex := index % 10

for i := 0; i <= targetIndex; i++ {
if i == targetIndex && nodes.Value >= 0 {
return nodes.Value, true
}
if nodes.Next == nil {
return 0, false
}
nodes = nodes.Next
}

return 0, false

}

0 comments on commit 71b6daa

Please sign in to comment.