diff --git a/README.md b/README.md index c30c6c1..5ee2e99 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,8 @@ Currently implemented containers are: search and remove, as well as advanced functions such as union, intersection, difference, subset, superset, and disjoint. - [x] `Vector` is a thin encapsulation based on `slice`. It provides functions such as insertion and deletion in the middle, range deletion, etc., and is still compatible with slices. -- [x] `DList` is a doubly linked list. +- [x] `DList` is a doubly linked list, supports push/popup at both ending. +- [x] `SList` is a singly linked list, support push/popup at the head and push at the tail. - [x] [SkipList](skiplist.md) is an ordered associative container that fills the gap where Go `map` only supports unordered. This is currently the fastest skip list I tested in GitHub, see [skiplist-survey](https://github.com/chen3feng/skiplist-survey) for performance comparison - [x] `Stack`, is a FILO container based on Slice implementation diff --git a/README_zh.md b/README_zh.md index 23e9fcb..7a2384d 100644 --- a/README_zh.md +++ b/README_zh.md @@ -34,7 +34,8 @@ import "github.com/chen3feng/stl4go" - [x] `Set` 集合。用 Go 自己的 map 封装了一个 `BuiltinSet`,提供了插入查找删除等基本操作,以及并集、交集、差集、子集、超集、不交集等高级功能。 - [x] `Vector` 是基于 slice 封装的向量。提供了中间插入删除、区间删除等功能,依然与 slice 兼容。 -- [x] `DList` 是双链表 +- [x] `DList` 是双链表容器,支持两端插入删除。 +- [x] `SList` 是单链表容器,支持头部插入删除及尾部插入。 - [x] [跳表(SkipList)](skiplist.md) 是一种有序的关联容器,可以填补 Go `map` 只支持无序的的空白。这是目前全 GitHub 最快的跳表,参见 [skiplist-survey](https://github.com/chen3feng/skiplist-survey)的性能比较 - [x] `Stack`,栈基于 Slice 实现 - [x] `Queue` 双向进出的队列,基于链表实现 diff --git a/dlist.go b/dlist.go index e6518bf..aa9a894 100644 --- a/dlist.go +++ b/dlist.go @@ -118,9 +118,12 @@ func (l *DList[T]) TryPopFront() (T, bool) { if l.length == 0 { return val, false } - val = l.head.next.value - l.head.next = l.head.next.next + node := l.head.next + val = node.value + l.head.next = node.next l.head.prev = &l.head + node.prev = nil + node.next = nil l.length-- return val, true } @@ -131,9 +134,12 @@ func (l *DList[T]) TryPopBack() (T, bool) { if l.length == 0 { return val, false } - val = l.head.prev.value + node := l.head.prev + val = node.value l.head.prev = l.head.prev.prev l.head.prev.next = &l.head + node.prev = nil + node.next = nil l.length-- return val, true } diff --git a/generated_doc.md b/generated_doc.md index dabb334..30ee132 100755 --- a/generated_doc.md +++ b/generated_doc.md @@ -150,6 +150,23 @@ Package stl4go is a generic container and algorithm library for go. - [func (q *Queue[T]) String() string](<#func-queuet-string>) - [func (q *Queue[T]) TryPopBack() (T, bool)](<#func-queuet-trypopback>) - [func (q *Queue[T]) TryPopFront() (T, bool)](<#func-queuet-trypopfront>) +- [type SList](<#type-slist>) + - [func SListOf[T any](values ...T) SList[T]](<#func-slistof>) + - [func (l *SList[T]) Back() T](<#func-slistt-back>) + - [func (l *SList[T]) Clear()](<#func-slistt-clear>) + - [func (l *SList[T]) ForEach(cb func(T))](<#func-slistt-foreach>) + - [func (l *SList[T]) ForEachIf(cb func(T) bool)](<#func-slistt-foreachif>) + - [func (l *SList[T]) ForEachMutable(cb func(*T))](<#func-slistt-foreachmutable>) + - [func (l *SList[T]) ForEachMutableIf(cb func(*T) bool)](<#func-slistt-foreachmutableif>) + - [func (l *SList[T]) Front() T](<#func-slistt-front>) + - [func (l *SList[T]) IsEmpty() bool](<#func-slistt-isempty>) + - [func (l *SList[T]) Iterate() MutableIterator[T]](<#func-slistt-iterate>) + - [func (l *SList[T]) Len() int](<#func-slistt-len>) + - [func (l *SList[T]) PopFront() T](<#func-slistt-popfront>) + - [func (l *SList[T]) PushBack(v T)](<#func-slistt-pushback>) + - [func (l *SList[T]) PushFront(v T)](<#func-slistt-pushfront>) + - [func (l *SList[T]) Reverse()](<#func-slistt-reverse>) + - [func (l *SList[T]) Values() []T](<#func-slistt-values>) - [type Set](<#type-set>) - [type Signed](<#type-signed>) - [type SkipList](<#type-skiplist>) @@ -1053,7 +1070,7 @@ func (l *DList[T]) Clear() Clear cleanup the list -### func \(\*DList\[T\]\) [ForEach]() +### func \(\*DList\[T\]\) [ForEach]() ```go func (l *DList[T]) ForEach(cb func(val T)) @@ -1061,7 +1078,7 @@ func (l *DList[T]) ForEach(cb func(val T)) ForEach iterate the list, apply each element to the cb callback function. -### func \(\*DList\[T\]\) [ForEachIf]() +### func \(\*DList\[T\]\) [ForEachIf]() ```go func (l *DList[T]) ForEachIf(cb func(val T) bool) @@ -1069,7 +1086,7 @@ func (l *DList[T]) ForEachIf(cb func(val T) bool) ForEachIf iterate the list, apply each element to the cb callback function, stop if cb returns false. -### func \(\*DList\[T\]\) [ForEachMutable]() +### func \(\*DList\[T\]\) [ForEachMutable]() ```go func (l *DList[T]) ForEachMutable(cb func(val *T)) @@ -1077,7 +1094,7 @@ func (l *DList[T]) ForEachMutable(cb func(val *T)) ForEachMutable iterate the list, apply pointer of each element to the cb callback function. -### func \(\*DList\[T\]\) [ForEachMutableIf]() +### func \(\*DList\[T\]\) [ForEachMutableIf]() ```go func (l *DList[T]) ForEachMutableIf(cb func(val *T) bool) @@ -1149,7 +1166,7 @@ func (l *DList[T]) String() string String convert the list to string -### func \(\*DList\[T\]\) [TryPopBack]() +### func \(\*DList\[T\]\) [TryPopBack]() ```go func (l *DList[T]) TryPopBack() (T, bool) @@ -1503,6 +1520,144 @@ func (q *Queue[T]) TryPopFront() (T, bool) TryPopFront tries popuping an element from the front of the queue. +## type [SList]() + +SList is a single linked list. + +```go +type SList[T any] struct { + // contains filtered or unexported fields +} +``` + +### func [SListOf]() + +```go +func SListOf[T any](values ...T) SList[T] +``` + +SListOf return a SList that contains values. + +### func \(\*SList\[T\]\) [Back]() + +```go +func (l *SList[T]) Back() T +``` + +Back returns the last element in the list. + +### func \(\*SList\[T\]\) [Clear]() + +```go +func (l *SList[T]) Clear() +``` + +Clear erases all elements from the container. After this call, Len\(\) returns zero. + +### func \(\*SList\[T\]\) [ForEach]() + +```go +func (l *SList[T]) ForEach(cb func(T)) +``` + +ForEach iterate the list, apply each element to the cb callback function. + +### func \(\*SList\[T\]\) [ForEachIf]() + +```go +func (l *SList[T]) ForEachIf(cb func(T) bool) +``` + +ForEachIf iterate the container, apply each element to the cb callback function, stop if cb returns false. + +### func \(\*SList\[T\]\) [ForEachMutable]() + +```go +func (l *SList[T]) ForEachMutable(cb func(*T)) +``` + +ForEachMutable iterate the container, apply pointer of each element to the cb callback function. + +### func \(\*SList\[T\]\) [ForEachMutableIf]() + +```go +func (l *SList[T]) ForEachMutableIf(cb func(*T) bool) +``` + +ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, stop if cb returns false. + +### func \(\*SList\[T\]\) [Front]() + +```go +func (l *SList[T]) Front() T +``` + +Front returns the first element in the list. + +### func \(\*SList\[T\]\) [IsEmpty]() + +```go +func (l *SList[T]) IsEmpty() bool +``` + +IsEmpty checks if the container has no elements. + +### func \(\*SList\[T\]\) [Iterate]() + +```go +func (l *SList[T]) Iterate() MutableIterator[T] +``` + +Iterate returns an iterator to the whole container. + +### func \(\*SList\[T\]\) [Len]() + +```go +func (l *SList[T]) Len() int +``` + +Len returns the number of elements in the container. + +### func \(\*SList\[T\]\) [PopFront]() + +```go +func (l *SList[T]) PopFront() T +``` + +PopFront popups an element from the front of the list. The list must be non\-empty\! + +### func \(\*SList\[T\]\) [PushBack]() + +```go +func (l *SList[T]) PushBack(v T) +``` + +PushBack pushed an element to the tail of the list. + +### func \(\*SList\[T\]\) [PushFront]() + +```go +func (l *SList[T]) PushFront(v T) +``` + +PushFront pushed an element to the front of the list. + +### func \(\*SList\[T\]\) [Reverse]() + +```go +func (l *SList[T]) Reverse() +``` + +Reverse reverses the order of all elements in the container. + +### func \(\*SList\[T\]\) [Values]() + +```go +func (l *SList[T]) Values() []T +``` + +Values copies all elements in the container to a slice and return it. + ## type [Set]() Set is a containers that store unique elements. @@ -1872,31 +2027,31 @@ Clear erases all elements from the vector. After this call, Len\(\) returns zero func (v Vector[T]) ForEach(cb func(val T)) ``` -ForEach iterate the list, apply each element to the cb callback function. +ForEach iterate the container, apply each element to the cb callback function. -### func \(Vector\[T\]\) [ForEachIf]() +### func \(Vector\[T\]\) [ForEachIf]() ```go func (v Vector[T]) ForEachIf(cb func(val T) bool) ``` -ForEachIf iterate the list, apply each element to the cb callback function, stop if cb returns false. +ForEachIf iterate the container, apply each element to the cb callback function, stop if cb returns false. -### func \(Vector\[T\]\) [ForEachMutable]() +### func \(Vector\[T\]\) [ForEachMutable]() ```go func (v Vector[T]) ForEachMutable(cb func(val *T)) ``` -ForEachMutable iterate the list, apply pointer of each element to the cb callback function. +ForEachMutable iterate the container, apply pointer of each element to the cb callback function. -### func \(Vector\[T\]\) [ForEachMutableIf]() +### func \(Vector\[T\]\) [ForEachMutableIf]() ```go func (v Vector[T]) ForEachMutableIf(cb func(val *T) bool) ``` -ForEachMutableIf iterate the list, apply pointer of each element to the cb callback function, stop if cb returns false. +ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, stop if cb returns false. ### func \(\*Vector\[T\]\) [Insert]() @@ -1916,21 +2071,21 @@ func (v *Vector[T]) IsEmpty() bool IsEmpty implements the Container interface. -### func \(Vector\[T\]\) [Iterate]() +### func \(Vector\[T\]\) [Iterate]() ```go func (v Vector[T]) Iterate() MutableIterator[T] ``` -Iterate returns an iterator to the whole vector. +Iterate returns an iterator to the whole container. -### func \(Vector\[T\]\) [IterateRange]() +### func \(Vector\[T\]\) [IterateRange]() ```go func (v Vector[T]) IterateRange(i, j int) MutableIterator[T] ``` -IterateRange returns an iterator to the range \[i, j\) of the vector. +IterateRange returns an iterator to the range \[i, j\) of the container. ### func \(\*Vector\[T\]\) [Len]() diff --git a/slist.go b/slist.go new file mode 100644 index 0000000..4581776 --- /dev/null +++ b/slist.go @@ -0,0 +1,185 @@ +package stl4go + +// SList is a single linked list. +type SList[T any] struct { + head *sListNode[T] + tail *sListNode[T] // To support Back and PushBack + length int +} + +type sListNode[T any] struct { + next *sListNode[T] + value T +} + +// SListOf return a SList that contains values. +func SListOf[T any](values ...T) SList[T] { + l := SList[T]{} + for i := range values { + l.PushBack(values[i]) + } + return l +} + +// IsEmpty checks if the container has no elements. +func (l *SList[T]) IsEmpty() bool { + return l.length == 0 +} + +// Len returns the number of elements in the container. +func (l *SList[T]) Len() int { + return l.length +} + +// Clear erases all elements from the container. After this call, Len() returns zero. +func (l *SList[T]) Clear() { + l.head = nil + l.tail = nil + l.length = 0 +} + +// Front returns the first element in the list. +func (l *SList[T]) Front() T { + return l.head.value +} + +// Back returns the last element in the list. +func (l *SList[T]) Back() T { + return l.tail.value +} + +// PushFront pushed an element to the front of the list. +func (l *SList[T]) PushFront(v T) { + node := sListNode[T]{l.head, v} + l.head = &node + if l.tail == nil { + l.tail = &node + } + l.length++ +} + +// PushBack pushed an element to the tail of the list. +func (l *SList[T]) PushBack(v T) { + node := sListNode[T]{nil, v} + if l.tail != nil { + l.tail.next = &node + } + l.tail = &node + if l.head == nil { + l.head = &node + } + l.length++ +} + +// PopFront popups an element from the front of the list. +// The list must be non-empty! +func (l *SList[T]) PopFront() T { + node := l.head + if node != nil { + l.head = node.next + if l.head == nil { + l.tail = nil + } + l.length-- + } + return node.value +} + +// Reverse reverses the order of all elements in the container. +func (l *SList[T]) Reverse() { + var head, tail *sListNode[T] + for node := l.head; node != nil; { + next := node.next + node.next = head + head = node + if tail == nil { + tail = node + } + node = next + } + l.head = head + l.tail = tail +} + +// Values copies all elements in the container to a slice and return it. +func (l *SList[T]) Values() []T { + s := make([]T, l.Len()) + for node, i := l.head, 0; node != nil; node = node.next { + s[i] = node.value + i++ + } + return s +} + +// InsertAfter inserts an element after the iterator into the list, +// return an iterator to the inserted element. +// func (l *SList[T]) InsertAfter(it Iterator[T], value T) MutableIterator[T] { +// // cause internal compiler error: panic: runtime error: invalid memory address or nil pointer dereference +// itp := it.(*sListIterator[T]) +// node := itp.node +// newNode := sListNode[T]{node.next, value} +// node.next = &newNode +// return &sListIterator[T]{&newNode} +// } + +// ForEach iterate the list, apply each element to the cb callback function. +func (l *SList[T]) ForEach(cb func(T)) { + for node := l.head; node != nil; node = node.next { + cb(node.value) + } +} + +// ForEachIf iterate the container, apply each element to the cb callback function, +// stop if cb returns false. +func (l *SList[T]) ForEachIf(cb func(T) bool) { + for node := l.head; node != nil; node = node.next { + if !cb(node.value) { + break + } + } +} + +// ForEachMutable iterate the container, apply pointer of each element to the cb callback function. +func (l *SList[T]) ForEachMutable(cb func(*T)) { + for node := l.head; node != nil; node = node.next { + cb(&node.value) + } +} + +// ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, +// stop if cb returns false. +func (l *SList[T]) ForEachMutableIf(cb func(*T) bool) { + for node := l.head; node != nil; node = node.next { + if !cb(&node.value) { + break + } + } +} + +// Iterate returns an iterator to the whole container. +func (l *SList[T]) Iterate() MutableIterator[T] { + it := sListIterator[T]{l.head} + return &it +} + +type sListIterator[T any] struct { + node *sListNode[T] +} + +func (it sListIterator[T]) IsNotEnd() bool { + return it.node != nil +} + +func (it *sListIterator[T]) MoveToNext() { + it.node = it.node.next +} + +func (it sListIterator[T]) Value() T { + return it.node.value +} + +func (it sListIterator[T]) Pointer() *T { + return &it.node.value +} + +// TODO: Sort diff --git a/slist_test.go b/slist_test.go new file mode 100644 index 0000000..a4bbfc5 --- /dev/null +++ b/slist_test.go @@ -0,0 +1,112 @@ +package stl4go + +import ( + "testing" +) + +func Test_DList_Interface(t *testing.T) { + sl := SList[int]{} + _ = Container(&sl) +} + +func Test_SList_Clean(t *testing.T) { + sl := SList[int]{} + sl.PushFront(1) + sl.Clear() + expectTrue(t, sl.IsEmpty()) + expectEq(t, sl.Len(), 0) +} + +func Test_SList_PushFront(t *testing.T) { + sl := SList[int]{} + for i := 1; i < 10; i++ { + sl.PushFront(i) + expectEq(t, sl.Front(), i) + expectEq(t, sl.Len(), i) + } +} + +func Test_SList_PushBack(t *testing.T) { + sl := SList[int]{} + for i := 1; i < 10; i++ { + sl.PushBack(i) + expectEq(t, sl.Back(), i) + expectEq(t, sl.Len(), i) + expectFalse(t, sl.IsEmpty()) + } +} + +func Test_SList_PopFront(t *testing.T) { + sl := SList[int]{} + sl.PushFront(1) + sl.PushFront(2) + expectEq(t, sl.PopFront(), 2) + expectEq(t, sl.PopFront(), 1) + expectPanic(t, func() { sl.PopFront() }) +} + +func Test_SList_Reverse(t *testing.T) { + sl := SListOf(1, 2, 3, 4) + sl.Reverse() + expectTrue(t, Equal(sl.Values(), []int{4, 3, 2, 1})) +} + +func Test_SList_ForEach(t *testing.T) { + sl := SListOf(1, 2, 3, 4) + i := 0 + sl.ForEach(func(v int) { + i++ + expectEq(t, v, i) + }) + expectEq(t, i, sl.Len()) +} + +func Test_SList_ForEachIf(t *testing.T) { + sl := SListOf(1, 2, 3, 4) + i := 0 + sl.ForEachIf(func(v int) bool { + i++ + expectEq(t, v, i) + return i < 3 + }) + expectEq(t, i, 3) +} + +func Test_SList_ForEachMutable(t *testing.T) { + sl := SListOf(1, 2, 3, 4) + i := 0 + sl.ForEachMutable(func(v *int) { + i++ + expectEq(t, *v, i) + *v = -*v + }) + expectEq(t, i, sl.Len()) + sl.ForEachMutable(func(v *int) { + expectLt(t, *v, 0) + }) +} + +func Test_SList_ForEachMutableIf(t *testing.T) { + sl := SListOf(1, 2, 3, 4) + i := 0 + sl.ForEachMutableIf(func(v *int) bool { + i++ + expectEq(t, *v, i) + return i < 3 + }) + expectEq(t, i, 3) +} + +func Test_SList_Iterate(t *testing.T) { + sl := SList[int]{} + sl.PushBack(1) + sl.PushBack(2) + sl.PushBack(3) + i := 0 + for it := sl.Iterate(); it.IsNotEnd(); it.MoveToNext() { + i++ + expectEq(t, it.Value(), i) + expectEq(t, *it.Pointer(), i) + } + expectEq(t, i, 3) +} diff --git a/vector.go b/vector.go index 60cc637..d21d27f 100644 --- a/vector.go +++ b/vector.go @@ -154,14 +154,15 @@ func (v *Vector[T]) RemoveLength(i int, len int) { v.RemoveRange(i, i+len) } -// ForEach iterate the list, apply each element to the cb callback function. +// ForEach iterate the container, apply each element to the cb callback function. func (v Vector[T]) ForEach(cb func(val T)) { for _, e := range v { cb(e) } } -// ForEachIf iterate the list, apply each element to the cb callback function, stop if cb returns false. +// ForEachIf iterate the container, apply each element to the cb callback function, +// stop if cb returns false. func (v Vector[T]) ForEachIf(cb func(val T) bool) { for _, e := range v { if !cb(e) { @@ -170,14 +171,15 @@ func (v Vector[T]) ForEachIf(cb func(val T) bool) { } } -// ForEachMutable iterate the list, apply pointer of each element to the cb callback function. +// ForEachMutable iterate the container, apply pointer of each element to the cb callback function. func (v Vector[T]) ForEachMutable(cb func(val *T)) { for i := range v { cb(&v[i]) } } -// ForEachMutableIf iterate the list, apply pointer of each element to the cb callback function, stop if cb returns false. +// ForEachMutableIf iterate the container, apply pointer of each element to the cb callback function, +// stop if cb returns false. func (v Vector[T]) ForEachMutableIf(cb func(val *T) bool) { for i := range v { if !cb(&v[i]) { @@ -186,12 +188,12 @@ func (v Vector[T]) ForEachMutableIf(cb func(val *T) bool) { } } -// Iterate returns an iterator to the whole vector. +// Iterate returns an iterator to the whole container. func (v Vector[T]) Iterate() MutableIterator[T] { return &vectorIterator[T]{v, 0} } -// IterateRange returns an iterator to the range [i, j) of the vector. +// IterateRange returns an iterator to the range [i, j) of the container. func (v Vector[T]) IterateRange(i, j int) MutableIterator[T] { return &vectorIterator[T]{v[i:j], 0} }