diff --git a/collections/linked_list.go b/collections/linked_list.go index a3f0042..7068116 100644 --- a/collections/linked_list.go +++ b/collections/linked_list.go @@ -1,38 +1,203 @@ package collections -type Item[T any] interface { - Less(T) bool -} +import ( + "fmt" + + "github.com/charlienet/go-mixed/locker" +) // 单链表节点 -type linkedNode[T Item[T]] struct { +type linkedNode[T any] struct { item T next *linkedNode[T] } // 双向链接节点 -type doubleLinkedNode[T Item[T]] struct { +type doubleLinkedNode[T any] struct { item T prev *linkedNode[T] next *linkedNode[T] } -type LinkedList[T Item[T]] struct { +type LinkedList[T any] struct { + mu locker.RWLocker head, tail *linkedNode[T] size int } // 初始化单向链表 -func NewLinkedList[T Item[T]]() *LinkedList[T] { - return &LinkedList[T]{} +func NewLinkedList[T any](vals ...T) *LinkedList[T] { + l := &LinkedList[T]{mu: locker.EmptyLocker} + l.Append(vals...) + + return l } -type DLinkedList[T Item[T]] struct { +// synchronized +func (l *LinkedList[T]) Synchronize() { + l.mu = locker.NewRWLocker() +} + +func (l *LinkedList[T]) Append(vals ...T) { + for _, v := range vals { + l.append(v) + } +} + +// prepend will prepend the list with a value, the reference node is Returned +func (l *LinkedList[T]) Prepend(vals ...T) { + for _, v := range vals { + l.prepend(v) + } +} + +func (l *LinkedList[T]) append(v T) { + n := createSingleNode(v) + + l.mu.Lock() + defer l.mu.Unlock() + + if l.head == nil { + l.head = n + } + + if l.tail != nil { + l.tail.next = n + } + + l.tail = n + l.size++ +} + +func (l *LinkedList[T]) prepend(v T) { + n := createSingleNode(v) + + l.mu.Lock() + defer l.mu.Unlock() + + if l.head != nil { + n.next = l.head + } + + if l.tail == nil { + l.tail = n + } + + l.head = n + l.size++ +} + +func (l *LinkedList[T]) PushHead() { +} + +func (l *LinkedList[T]) PushTail() { + +} + +func (l *LinkedList[T]) Exist(v T) bool { + ret := false + l.ForEach(func(t T) bool { + // if t == v { + // ret = true + // return true + // } + + return false + }) + + return ret +} + +func (l *LinkedList[T]) RemoveAt(index int) { + var i int + var prev *linkedNode[T] + + prev = l.head + for current := l.head; current != nil; { + + if i == index { + prev.next = current.next + current.next = nil + + l.size-- + return + } + + prev = current + current = current.next + i++ + } +} + +func (l *LinkedList[T]) IsEmpty() bool { + return l.size == 0 +} + +func (l *LinkedList[T]) Size() int { + return l.size +} + +func (l *LinkedList[T]) GetAt(i int) T { + if i <= l.Size() { + var n int + for current := l.head; current != nil; current = current.next { + if n == i { + return current.item + } + n++ + } + } + + return *new(T) +} + +func (l *LinkedList[T]) ForEach(fn func(T) bool) { + for current := l.head; current != nil; current = current.next { + if fn(current.item) { + break + } + } +} + +func (l *LinkedList[T]) Clear() { + l.head = nil + l.tail = nil + l.size = 0 +} + +func (l *LinkedList[T]) ToList() []T { + ret := make([]T, 0, l.size) + l.ForEach(func(t T) bool { + ret = append(ret, t) + return false + }) + + return ret +} + +func (l *LinkedList[T]) String() string { + return fmt.Sprint(l.ToList()) +} + +func (l *LinkedList[T]) remove(n *linkedNode[T]) { + n.next = nil + l.size-- +} + +type DLinkedList[T any] struct { head, tail *doubleLinkedNode[T] size int } // 初始化双向链表 -func NewDoubleLinkedLis[T Item[T]]() *DLinkedList[T] { +func NewDoubleLinkedLis[T any]() *DLinkedList[T] { return &DLinkedList[T]{} } + +func createSingleNode[T any](v T) *linkedNode[T] { + return &linkedNode[T]{item: v} +} + +func createDoubleNode[T any](v T) *doubleLinkedNode[T] { + return &doubleLinkedNode[T]{item: v} +} diff --git a/collections/linked_list_test.go b/collections/linked_list_test.go new file mode 100644 index 0000000..5b153dc --- /dev/null +++ b/collections/linked_list_test.go @@ -0,0 +1,36 @@ +package collections + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewLinkdList(t *testing.T) { + l := NewLinkedList(1, 2, 3, 4, 5) + + l.Append(55) + t.Log(l) + + t.Log(NewLinkedList("a", "b", "c", "d")) +} + +func TestLinkedListSize(t *testing.T) { + ll := NewLinkedList[int]() + + ll.Append(5) + ll.Append(6) + ll.Append(7) + + assert.Equal(t, 3, ll.Size()) + + ll.Prepend(8, 9, 10) + assert.Equal(t, 6, ll.Size()) + + ll.RemoveAt(1) + assert.Equal(t, 5, ll.Size()) + t.Log(ll) + + ll.RemoveAt(ll.Size() - 1) + t.Log(ll) +} diff --git a/collections/options.go b/collections/options.go new file mode 100644 index 0000000..2cbef0d --- /dev/null +++ b/collections/options.go @@ -0,0 +1,11 @@ +package collections + +import "github.com/charlienet/go-mixed/locker" + +type options struct { + mu locker.RWLocker +} + +func emptyLocker() locker.RWLocker { + return locker.EmptyLocker +}