实现一个支持泛型的链表
This commit is contained in:
parent
d71a05e4b1
commit
5f49bde3ae
3 changed files with 508 additions and 0 deletions
251
glist/linkedlist.go
Normal file
251
glist/linkedlist.go
Normal file
|
@ -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
|
||||||
|
}
|
209
glist/linkedlist_test.go
Normal file
209
glist/linkedlist_test.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
48
glist/list.go
Normal file
48
glist/list.go
Normal file
|
@ -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
|
||||||
|
}
|
Reference in a new issue