mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-23 13:52:26 +08:00
feat: add datastructure package and list implementation
This commit is contained in:
208
datastructure/list.go
Normal file
208
datastructure/list.go
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
|
// Package datastructure implements some data structure. eg. list, linklist, stack, queue, tree, graph.
|
||||||
|
package datastructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type List[T any] struct {
|
||||||
|
data []T
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewList return a pointer of List
|
||||||
|
func NewList[T any](data []T) *List[T] {
|
||||||
|
return &List[T]{data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data return list data
|
||||||
|
func (l *List[T]) Data() []T {
|
||||||
|
return l.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueOf return the value pointer at index of list data.
|
||||||
|
func (l *List[T]) ValueOf(index int) (*T, bool) {
|
||||||
|
if index < 0 || index >= len(l.data) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return &l.data[index], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexOf reture the index of value. if not found return -1
|
||||||
|
func (l *List[T]) IndexOf(value T) int {
|
||||||
|
index := -1
|
||||||
|
data := l.data
|
||||||
|
for i, v := range data {
|
||||||
|
if reflect.DeepEqual(v, value) {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push append value to the list data
|
||||||
|
func (l *List[T]) Push(value T) {
|
||||||
|
l.data = append(l.data, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertAtFirst insert value into list at first index
|
||||||
|
func (l *List[T]) InsertAtFirst(value T) {
|
||||||
|
l.InsertAt(0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertAtLast insert value into list at last index
|
||||||
|
func (l *List[T]) InsertAtLast(value T) {
|
||||||
|
l.InsertAt(len(l.data), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertAt insert value into list at index
|
||||||
|
func (l *List[T]) InsertAt(index int, value T) {
|
||||||
|
data := l.data
|
||||||
|
size := len(data)
|
||||||
|
|
||||||
|
if index < 0 || index > size {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopFirst delete the first value of list and return it
|
||||||
|
func (l *List[T]) PopFirst() (*T, bool) {
|
||||||
|
if len(l.data) == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
v := l.data[0]
|
||||||
|
l.DeleteAt(0)
|
||||||
|
|
||||||
|
return &v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopLast delete the last value of list and return it
|
||||||
|
func (l *List[T]) PopLast() (*T, bool) {
|
||||||
|
size := len(l.data)
|
||||||
|
if size == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
v := l.data[size-1]
|
||||||
|
l.DeleteAt(size - 1)
|
||||||
|
|
||||||
|
return &v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAt delete the value of list at index
|
||||||
|
func (l *List[T]) DeleteAt(index int) {
|
||||||
|
data := l.data
|
||||||
|
size := len(data)
|
||||||
|
if index < 0 || index > size-1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if index == size-1 {
|
||||||
|
data = append(data[:index])
|
||||||
|
} else {
|
||||||
|
data = append(data[:index], data[index+1:]...)
|
||||||
|
}
|
||||||
|
l.data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertAt insert value into list at index, index shoud between 0 and list size -1
|
||||||
|
func (l *List[T]) UpdateAt(index int, value T) {
|
||||||
|
data := l.data
|
||||||
|
size := len(data)
|
||||||
|
|
||||||
|
if index < 0 || index >= size {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqutalTo compare list to other list, use reflect.DeepEqual
|
||||||
|
func (l *List[T]) EqutalTo(other *List[T]) bool {
|
||||||
|
if len(l.data) != len(other.data) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(l.data); i++ {
|
||||||
|
if !reflect.DeepEqual(l.data[i], other.data[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty check if the list is empty or not
|
||||||
|
func (l *List[T]) IsEmpty() bool {
|
||||||
|
return len(l.data) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone return a copy of list
|
||||||
|
func (l *List[T]) Clear() {
|
||||||
|
l.data = make([]T, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone return a copy of list
|
||||||
|
func (l *List[T]) Clone() *List[T] {
|
||||||
|
cl := &List[T]{data: make([]T, len(l.data))}
|
||||||
|
copy(cl.data, l.data)
|
||||||
|
|
||||||
|
return cl
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge two list, return new list, don't change original list
|
||||||
|
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||||
|
l1, l2 := len(l.data), len(other.data)
|
||||||
|
ml := &List[T]{data: make([]T, l1+l2, l1+l2)}
|
||||||
|
data := append([]T{}, append(l.data, other.data...)...)
|
||||||
|
ml.data = data
|
||||||
|
|
||||||
|
return ml
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size return number of list data items
|
||||||
|
func (l *List[T]) Size() int {
|
||||||
|
return len(l.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the value of index i and j in list
|
||||||
|
func (l *List[T]) Swap(i, j int) {
|
||||||
|
size := len(l.data)
|
||||||
|
if i < 0 || i >= size || j < 0 || j >= size {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the item order of list
|
||||||
|
func (l *List[T]) Reverse() {
|
||||||
|
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unique remove duplicate items in list
|
||||||
|
func (l *List[T]) Unique() {
|
||||||
|
data := l.data
|
||||||
|
size := len(data)
|
||||||
|
|
||||||
|
uniqueData := make([]T, 0, 0)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
value := data[i]
|
||||||
|
skip := true
|
||||||
|
for _, v := range uniqueData {
|
||||||
|
if reflect.DeepEqual(value, v) {
|
||||||
|
skip = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if skip {
|
||||||
|
uniqueData = append(uniqueData, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.data = uniqueData
|
||||||
|
}
|
||||||
242
datastructure/list_test.go
Normal file
242
datastructure/list_test.go
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
package datastructure
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/duke-git/lancet/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListData(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestListData")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValueOf(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestValueOf")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
v, ok := list.ValueOf(0)
|
||||||
|
assert.Equal(1, *v)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
|
_, ok = list.ValueOf(3)
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexOf(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIndexOf")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
i := list.IndexOf(1)
|
||||||
|
assert.Equal(0, i)
|
||||||
|
|
||||||
|
i = list.IndexOf(4)
|
||||||
|
assert.Equal(-1, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPush(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPush")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
list.Push(4)
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertAtFirst(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestInsertAtFirst")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
list.InsertAtFirst(0)
|
||||||
|
|
||||||
|
assert.Equal([]int{0, 1, 2, 3}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertAtLast(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestInsertAtLast")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
list.InsertAtLast(4)
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsertAt(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestInsertAt")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
|
||||||
|
list.InsertAt(-1, 0)
|
||||||
|
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||||
|
|
||||||
|
list.InsertAt(4, 0)
|
||||||
|
assert.Equal([]int{1, 2, 3}, list.Data())
|
||||||
|
|
||||||
|
list.InsertAt(0, 0)
|
||||||
|
assert.Equal([]int{0, 1, 2, 3}, list.Data())
|
||||||
|
|
||||||
|
list.InsertAt(4, 4)
|
||||||
|
assert.Equal([]int{0, 1, 2, 3, 4}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPopFirst(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPopFirst")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
v, ok := list.PopFirst()
|
||||||
|
assert.Equal(1, *v)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal([]int{2, 3}, list.Data())
|
||||||
|
|
||||||
|
list2 := NewList([]int{})
|
||||||
|
v, ok = list2.PopFirst()
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
assert.Equal([]int{}, list2.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPopLast(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestPopLast")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3})
|
||||||
|
v, ok := list.PopLast()
|
||||||
|
assert.Equal(3, *v)
|
||||||
|
assert.Equal(true, ok)
|
||||||
|
assert.Equal([]int{1, 2}, list.Data())
|
||||||
|
|
||||||
|
list2 := NewList([]int{})
|
||||||
|
v, ok = list2.PopLast()
|
||||||
|
assert.Equal(false, ok)
|
||||||
|
assert.Equal([]int{}, list2.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteAt(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestDeleteAt")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
list.DeleteAt(-1)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.DeleteAt(4)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.DeleteAt(0)
|
||||||
|
assert.Equal([]int{2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.DeleteAt(2)
|
||||||
|
assert.Equal([]int{2, 3}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateAt(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUpdateAt")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
list.UpdateAt(-1, 0)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.UpdateAt(4, 0)
|
||||||
|
assert.Equal([]int{1, 2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.UpdateAt(0, 5)
|
||||||
|
assert.Equal([]int{5, 2, 3, 4}, list.Data())
|
||||||
|
|
||||||
|
list.UpdateAt(3, 1)
|
||||||
|
assert.Equal([]int{5, 2, 3, 1}, list.Data())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEqutalTo(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestEqutalTo")
|
||||||
|
|
||||||
|
list1 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list2 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list3 := NewList([]int{1, 2, 3})
|
||||||
|
|
||||||
|
assert.Equal(true, list1.EqutalTo(list2))
|
||||||
|
assert.Equal(false, list1.EqutalTo(list3))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsEmpty(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsEmpty")
|
||||||
|
|
||||||
|
list1 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list2 := NewList([]int{})
|
||||||
|
|
||||||
|
assert.Equal(false, list1.IsEmpty())
|
||||||
|
assert.Equal(true, list2.IsEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsClear(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestIsClear")
|
||||||
|
|
||||||
|
list1 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list1.Clear()
|
||||||
|
empty := NewList([]int{})
|
||||||
|
|
||||||
|
assert.Equal(empty, list1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClone(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestClone")
|
||||||
|
|
||||||
|
list1 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list2 := list1.Clone()
|
||||||
|
|
||||||
|
assert.Equal(true, list1.EqutalTo(list2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerge(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestMerge")
|
||||||
|
|
||||||
|
list1 := NewList([]int{1, 2, 3, 4})
|
||||||
|
list2 := NewList([]int{4, 5, 6})
|
||||||
|
expected := NewList([]int{1, 2, 3, 4, 4, 5, 6})
|
||||||
|
|
||||||
|
list3 := list1.Merge(list2)
|
||||||
|
assert.Equal(true, expected.EqutalTo(list3))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSize(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSize")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3, 4})
|
||||||
|
empty := NewList([]int{})
|
||||||
|
|
||||||
|
assert.Equal(4, list.Size())
|
||||||
|
assert.Equal(0, empty.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSwap(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestSwap")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3, 4})
|
||||||
|
expected := NewList([]int{4, 2, 3, 1})
|
||||||
|
|
||||||
|
list.Swap(0, 3)
|
||||||
|
|
||||||
|
assert.Equal(true, expected.EqutalTo(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReverse(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestReverse")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 3, 4})
|
||||||
|
expected := NewList([]int{4, 3, 2, 1})
|
||||||
|
|
||||||
|
list.Reverse()
|
||||||
|
|
||||||
|
assert.Equal(true, expected.EqutalTo(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnique(t *testing.T) {
|
||||||
|
assert := internal.NewAssert(t, "TestUnique")
|
||||||
|
|
||||||
|
list := NewList([]int{1, 2, 2, 3, 4})
|
||||||
|
expected := NewList([]int{1, 2, 3, 4})
|
||||||
|
|
||||||
|
list.Unique()
|
||||||
|
|
||||||
|
assert.Equal(true, expected.EqutalTo(list))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user