mirror of
https://github.com/charlienet/go-mixed.git
synced 2025-07-18 08:32:40 +08:00
linked list
This commit is contained in:
@ -1,38 +1,203 @@
|
|||||||
package collections
|
package collections
|
||||||
|
|
||||||
type Item[T any] interface {
|
import (
|
||||||
Less(T) bool
|
"fmt"
|
||||||
}
|
|
||||||
|
"github.com/charlienet/go-mixed/locker"
|
||||||
|
)
|
||||||
|
|
||||||
// 单链表节点
|
// 单链表节点
|
||||||
type linkedNode[T Item[T]] struct {
|
type linkedNode[T any] struct {
|
||||||
item T
|
item T
|
||||||
next *linkedNode[T]
|
next *linkedNode[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 双向链接节点
|
// 双向链接节点
|
||||||
type doubleLinkedNode[T Item[T]] struct {
|
type doubleLinkedNode[T any] struct {
|
||||||
item T
|
item T
|
||||||
prev *linkedNode[T]
|
prev *linkedNode[T]
|
||||||
next *linkedNode[T]
|
next *linkedNode[T]
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkedList[T Item[T]] struct {
|
type LinkedList[T any] struct {
|
||||||
|
mu locker.RWLocker
|
||||||
head, tail *linkedNode[T]
|
head, tail *linkedNode[T]
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化单向链表
|
// 初始化单向链表
|
||||||
func NewLinkedList[T Item[T]]() *LinkedList[T] {
|
func NewLinkedList[T any](vals ...T) *LinkedList[T] {
|
||||||
return &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]
|
head, tail *doubleLinkedNode[T]
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化双向链表
|
// 初始化双向链表
|
||||||
func NewDoubleLinkedLis[T Item[T]]() *DLinkedList[T] {
|
func NewDoubleLinkedLis[T any]() *DLinkedList[T] {
|
||||||
return &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}
|
||||||
|
}
|
||||||
|
36
collections/linked_list_test.go
Normal file
36
collections/linked_list_test.go
Normal file
@ -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)
|
||||||
|
}
|
11
collections/options.go
Normal file
11
collections/options.go
Normal file
@ -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
|
||||||
|
}
|
Reference in New Issue
Block a user