diff --git a/glist/linkedlist.go b/glist/linkedlist.go new file mode 100644 index 0000000..fdacafe --- /dev/null +++ b/glist/linkedlist.go @@ -0,0 +1,251 @@ +package glist + +import ( + "math" +) + +const ( + // CAPACITY 链表的最大容量 + CAPACITY uint = math.MaxUint + ZERO = uint(0) //uint类型的0 +) + +// Node 链表中的一个结点 +type Node[E any] struct { + Element E //保存的内容 + Prev *Node[E] //前一个结点 + Next *Node[E] //后一个结点 +} + +// Clone 克隆Node,返回的Node的Prev和Next均为nil,Element保持不变 +func (n *Node[E]) Clone() *Node[E] { + node := &Node[E]{ + Element: n.Element, + Prev: nil, + Next: nil, + } + return node +} + +// LinkedList 链表,实现了List +type LinkedList[E any] struct { + Len uint //链表中元素个数 + First *Node[E] //头指针 + Last *Node[E] //尾指针 +} + +// NewLinkedList 创建一个链表, +//列表的最大容量为uint类型的最大值 +func NewLinkedList[E any]() *LinkedList[E] { + return &LinkedList[E]{ + Len: 0, + First: nil, + Last: nil, + } +} + +func (l *LinkedList[E]) Size() uint { + return l.Len +} + +func (l *LinkedList[E]) IsEmpty() bool { + return l.Len == 0 +} + +func (l *LinkedList[E]) IsNotEmpty() bool { + return l.Len != 0 +} + +func (l *LinkedList[E]) Append(element E) bool { + //超出最大值无法添加 + if l.Len == CAPACITY { + return false + } + node := &Node[E]{ + Element: element, + Prev: nil, + Next: nil, + } + //链表为空,头指针指向该结点 + if l.First == nil { + l.First = node + l.Last = node + } else { + //链表不为空,添加到尾部 + node.Prev = l.Last + l.Last.Next = node + l.Last = node + } + l.Len++ + return true +} + +func (l *LinkedList[E]) Insert(index uint, element E) bool { + //当前size已经达到最大值或者索引越界 + if l.Len == CAPACITY || index > l.Len { + return false + } + node := &Node[E]{ + Element: element, + Prev: nil, + Next: nil, + } + //插入头部 + if index == 0 { + if l.First == nil { + //链表为空 + l.First = node + l.Last = node + } else { + //链表不为空 + node.Next = l.First + l.First.Prev = node + l.First = node + } + } else if index == l.Len { + //插入尾部 + l.Last.Next = node + node.Prev = l.Last + l.Last = node + } else { + var prev *Node[E] + head := l.First + for i := ZERO; i < index; i++ { + prev = head + head = head.Next + } + node.Next = head + node.Prev = prev + prev.Next = node + head.Prev = node + } + l.Len++ + return true +} + +func (l *LinkedList[E]) Remove(index uint) bool { + if index >= l.Len { + return false + } + head := l.First + var prev *Node[E] + for i := ZERO; i < index; i++ { + prev = head + head = head.Next + } + //删除第一个结点 + if head == l.First { + l.First.Next = nil + l.First = head.Next + } else if head == l.Last { + //删除最后一个结点 + l.Last = prev + l.Last.Next = nil + } else { + prev.Next = head.Next + head.Next.Prev = prev + } + l.Len-- + return true +} + +func (l *LinkedList[E]) Get(index uint) *E { + if index >= l.Len { + return nil + } + node := l.First + for i := ZERO; i < index; i++ { + node = node.Next + } + return &(node.Element) +} + +func (l *LinkedList[E]) Set(index uint, element E) bool { + if index >= l.Len { + return false + } + node := l.First + for i := ZERO; i < index; i++ { + node = node.Next + } + node.Element = element + return true +} + +func (l *LinkedList[E]) PushBack(element E) bool { + return l.Append(element) +} + +func (l *LinkedList[E]) PushFront(element E) bool { + return l.Insert(0, element) +} + +func (l *LinkedList[E]) PopBack() *E { + //链表为空 + if l.Len == 0 { + return nil + } + node := l.Last + //只有一个元素 + if l.Len == 1 { + l.Last = nil + l.First = nil + } else { + l.Last = node.Prev + l.Last.Next = nil + } + l.Len-- + return &(node.Element) +} + +func (l *LinkedList[E]) PopFront() *E { + if l.Len == 0 { + return nil + } + node := l.First + if l.Len == 1 { + l.First = nil + l.Last = nil + } else { + l.First = node.Next + l.First.Prev = nil + } + l.Len-- + return &(node.Element) +} + +func (l *LinkedList[E]) PullBack() *E { + if l.Len == 0 { + return nil + } + return &(l.Last.Element) +} + +func (l *LinkedList[E]) PullFront() *E { + if l.Len == 0 { + return nil + } + return &(l.First.Element) +} + +// Iterator 获取该链表的迭代器 +func (l *LinkedList[E]) Iterator() Iterator[E] { + return &LinkedListIterator[E]{next: l.First} +} + +type LinkedListIterator[E any] struct { + next *Node[E] +} + +func (l *LinkedListIterator[E]) Has() bool { + return l.next != nil +} + +func (l *LinkedListIterator[E]) Next() E { + e := l.next + if e == nil { + panic("iterator is empty.") + } + l.next = e.Next + return e.Element +} diff --git a/glist/linkedlist_test.go b/glist/linkedlist_test.go new file mode 100644 index 0000000..b05b50b --- /dev/null +++ b/glist/linkedlist_test.go @@ -0,0 +1,209 @@ +package glist + +import ( + "math/rand" + "reflect" + "testing" +) + +func checkListElement[T comparable](list *LinkedList[T], items []T, t *testing.T) { + if list.Len != uint(len(items)) { + t.Errorf("list Len= %d, items Len = %d.", list.Len, len(items)) + } + i := 0 + for it := list.Iterator(); it.Has(); { + e := it.Next() + if e != items[i] { + t.Errorf("index=%d,except:%v, but got:%v", i, items[i], e) + } + i++ + } +} + +func TestLinkedListIterator_Has(t *testing.T) { + //空列表 + t.Run("empty list", func(t *testing.T) { + emptyList := NewLinkedList[int]() + it := emptyList.Iterator() + if it.Has() { + t.Errorf("iterator should empty, but not") + } + }) + //非空列表 + t.Run("non-empty list", func(t *testing.T) { + list := NewLinkedList[int]() + list.Append(1) + list.Append(2) + it := list.Iterator() + if !(it.Has()) { + t.Errorf("iterator should not empty, but not") + } + it.Next() + it.Next() + if it.Has() { + t.Errorf("iterator should empty, but not") + } + }) +} + +func TestLinkedListIterator_Next(t *testing.T) { + t.Run("empty list", func(t *testing.T) { + defer func() { + if p := recover(); p == nil { + t.Errorf("iterator is empty, should panic.") + } + }() + emptyList := NewLinkedList[int]() + it := emptyList.Iterator() + it.Next() + }) + + t.Run("non-empty list", func(t *testing.T) { + defer func() { + if p := recover(); p != nil { + t.Errorf("iterator is non-empty, should no panic.") + } + }() + list := NewLinkedList[int]() + times := rand.Int() % 20 //20次以内 + for i := times; i >= 0; i-- { + list.Append(i) + } + it := list.Iterator() + for i := times; i >= 0; i-- { + it.Next() + } + }) +} + +func TestLinkedList_Append(t *testing.T) { + var sliceWithTenNum [10]int + for i := 0; i < 10; i++ { + sliceWithTenNum[i] = i + } + tests := []struct { + name string + input []int + }{ + {"Append 0 value", []int{}}, + {"Append 10 value", sliceWithTenNum[:]}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + list := NewLinkedList[int]() + for _, v := range tt.input { + list.Append(v) + } + checkListElement(list, tt.input, t) + }) + } +} + +func TestLinkedList_Size(t *testing.T) { + tests := []struct { + name string + want uint + }{ + {"empty list", 0}, + {"10 values list", 10}, + {"20 values list", 20}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + num := tt.want + list := NewLinkedList[int]() + for i := uint(0); i < num; i++ { + list.Append(int(i)) + } + if got := list.Size(); got != tt.want { + t.Errorf("Size() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestLinkedList_IsEmpty(t *testing.T) { + nonEmpty := NewLinkedList[int]() + nonEmpty.Append(1) + + tests := []struct { + name string + list *LinkedList[int] + want bool + }{ + {"empty list", NewLinkedList[int](), true}, + {"non-empty list", nonEmpty, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := tt.list + if got := l.IsEmpty(); got != tt.want { + t.Errorf("IsEmpty() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestLinkedList_Remove(t *testing.T) { + tests := []struct { + name string + listNum int + args uint + want bool + values []int + }{ + {"empty list", 0, 0, false, nil}, + {"index gather than Len", 0, 1, false, nil}, + {"1 value list:delete index 0", 1, 0, true, []int{}}, + {"10 value list:delete index 0", 10, 0, true, []int{1, 2, 3, 4, 5, 6, 7, 8, 9}}, + {"10 value list:delete index 5", 10, 5, true, []int{0, 1, 2, 3, 4, 6, 7, 8, 9}}, + {"10 value list:delete index 9", 10, 9, true, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := NewLinkedList[int]() + for i := 0; i < tt.listNum; i++ { + l.Append(i) + } + if got := l.Remove(tt.args); got != tt.want { + t.Errorf("Remove() = %v, want %v", got, tt.want) + } + if tt.want { + checkListElement(l, tt.values, t) + } + }) + } +} + +func TestLinkedList_Get(t *testing.T) { + tests := []struct { + name string + listNum int + args uint + want int + }{ + {"empty list,index 0", 0, 0, -1}, + {"empty list,index 1", 0, 1, -1}, + {"1 value list, index 0", 1, 0, 0}, + {"10 value list, index 0", 10, 0, 0}, + {"10 value list, index 5", 10, 5, 5}, + {"10 value list, index 9", 10, 9, 9}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := NewLinkedList[int]() + for i := 0; i < tt.listNum; i++ { + l.Append(i) + } + want := new(int) + if tt.want == -1 { + want = nil + } else { + *want = tt.want + } + if got := l.Get(tt.args); !reflect.DeepEqual(got, want) { + t.Errorf("Get() = %v, want %v", got, want) + } + }) + } +} diff --git a/glist/list.go b/glist/list.go new file mode 100644 index 0000000..0f1da8d --- /dev/null +++ b/glist/list.go @@ -0,0 +1,48 @@ +package glist + +// List 一个基本的列表 +type List[E any] interface { + // Size 获取列表中数据个数 + Size() uint + //IsEmpty 判断列表是否为空,如果为空,返回true,否则返回false + IsEmpty() bool + // IsNotEmpty 判断列表是否非空,如果列表不为空,返回true,否则返回false + IsNotEmpty() bool + // Append 向列表尾部添加一个元素 + Append(element E) bool + // Insert 向列表指定索引处插入一个元素,如果插入成功返回true,否则返回false + Insert(index uint, element E) bool + // Remove 从列表中移除元素element,如果元素不存在,则返回false + Remove(index uint) bool + // Get 从列表中获取索引为index元素的指针,索引从0开始,如果索引超出范围则返回nil + Get(index uint) *E + // Set 改变列表中索引为index的元素的值,如果索引超出范围则返回false + Set(index uint, element E) bool + // Iterator 获取列表的迭代器 + Iterator() Iterator[E] +} + +// Queue 队列 +type Queue[E any] interface { + List[E] + // PushBack 队列尾部添加元素,添加成功返回true + PushBack(element E) bool + // PushFront 队列头部添加元素,添加成功返回true + PushFront(element E) bool + // PopBack 删除队列尾部的元素,返回被删除的元素的指针,如果队列为空,则返回nil + PopBack() *E + // PopFront 删除队列头部的元素,返回被删除元素的指针,如果队列为空,返回nil + PopFront() *E + // PullBack 获取队列尾部的元素的指针,不会删除,如果队列为空,返回nil + PullBack() *E + // PullFront 获取队列头部的元素的指针,不会删除,如果队列为空,返回nil + PullFront() *E +} + +// Iterator 列表迭代器 +type Iterator[E any] interface { + // Has 是否还有元素 + Has() bool + // Next 获取元素 + Next() E +}