完善: linkedlist
This commit is contained in:
87
list/linked_list/iterator.go
Normal file
87
list/linked_list/iterator.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package linkedlist
|
||||
|
||||
type Iterator struct {
|
||||
ll *LinkedList
|
||||
cur *Node
|
||||
}
|
||||
|
||||
func (iter *Iterator) Value() interface{} {
|
||||
return iter.cur.value
|
||||
}
|
||||
|
||||
func (iter *Iterator) Prev() bool {
|
||||
if iter.cur == iter.ll.head {
|
||||
return false
|
||||
}
|
||||
iter.cur = iter.cur.prev
|
||||
return iter.cur != iter.ll.head
|
||||
}
|
||||
|
||||
func (iter *Iterator) Next() bool {
|
||||
if iter.cur == iter.ll.tail {
|
||||
return false
|
||||
}
|
||||
iter.cur = iter.cur.next
|
||||
return iter.cur != iter.ll.tail
|
||||
}
|
||||
|
||||
func (iter *Iterator) MoveToHead() {
|
||||
iter.cur = iter.ll.head
|
||||
}
|
||||
|
||||
func (iter *Iterator) MoveToTail() {
|
||||
iter.cur = iter.ll.tail
|
||||
}
|
||||
|
||||
type CircularIterator struct {
|
||||
pl *LinkedList
|
||||
cur *Node
|
||||
}
|
||||
|
||||
func (iter *CircularIterator) Value() interface{} {
|
||||
return iter.cur.value
|
||||
}
|
||||
|
||||
func (iter *CircularIterator) Prev() bool {
|
||||
if iter.pl.size == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if iter.cur == iter.pl.head {
|
||||
iter.cur = iter.pl.tail.prev
|
||||
return true
|
||||
}
|
||||
|
||||
iter.cur = iter.cur.prev
|
||||
if iter.cur == iter.pl.head {
|
||||
iter.cur = iter.pl.tail.prev
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (iter *CircularIterator) Next() bool {
|
||||
if iter.pl.size == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if iter.cur == iter.pl.tail {
|
||||
iter.cur = iter.pl.head.next
|
||||
return true
|
||||
}
|
||||
|
||||
iter.cur = iter.cur.next
|
||||
if iter.cur == iter.pl.tail {
|
||||
iter.cur = iter.pl.head.next
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (iter *CircularIterator) MoveToHead() {
|
||||
iter.cur = iter.pl.head
|
||||
}
|
||||
|
||||
func (iter *CircularIterator) MoveToTail() {
|
||||
iter.cur = iter.pl.tail
|
||||
}
|
||||
454
list/linked_list/linked_list.go
Normal file
454
list/linked_list/linked_list.go
Normal file
@@ -0,0 +1,454 @@
|
||||
package linkedlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
prev *Node
|
||||
next *Node
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (node *Node) Value() interface{} {
|
||||
return node.value
|
||||
}
|
||||
|
||||
type LinkedList struct {
|
||||
head *Node
|
||||
tail *Node
|
||||
size uint
|
||||
}
|
||||
|
||||
func New() *LinkedList {
|
||||
l := &LinkedList{}
|
||||
l.head = &Node{}
|
||||
l.head.prev = nil
|
||||
|
||||
l.tail = &Node{}
|
||||
l.tail.next = nil
|
||||
|
||||
l.head.next = l.tail
|
||||
l.tail.prev = l.head
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *LinkedList) Iterator() *Iterator {
|
||||
return &Iterator{ll: l, cur: l.head}
|
||||
}
|
||||
|
||||
func (l *LinkedList) CircularIterator() *CircularIterator {
|
||||
return &CircularIterator{pl: l, cur: l.head}
|
||||
}
|
||||
|
||||
func (l *LinkedList) Clear() {
|
||||
l.head.next = nil
|
||||
l.tail.prev = nil
|
||||
l.size = 0
|
||||
}
|
||||
|
||||
func (l *LinkedList) Empty() bool {
|
||||
return l.size == 0
|
||||
}
|
||||
|
||||
func (l *LinkedList) Size() uint {
|
||||
return l.size
|
||||
}
|
||||
|
||||
func (l *LinkedList) PushFront(values ...interface{}) {
|
||||
|
||||
var node *Node
|
||||
l.size += uint(len(values))
|
||||
for _, v := range values {
|
||||
node = &Node{}
|
||||
node.value = v
|
||||
|
||||
hnext := l.head.next
|
||||
hnext.prev = node
|
||||
|
||||
node.next = hnext
|
||||
node.prev = l.head
|
||||
l.head.next = node
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LinkedList) PushBack(values ...interface{}) {
|
||||
|
||||
var node *Node
|
||||
l.size += uint(len(values))
|
||||
for _, v := range values {
|
||||
node = &Node{}
|
||||
node.value = v
|
||||
|
||||
tprev := l.tail.prev
|
||||
tprev.next = node
|
||||
|
||||
node.prev = tprev
|
||||
node.next = l.tail
|
||||
l.tail.prev = node
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LinkedList) PopFront() (result interface{}, found bool) {
|
||||
if l.size != 0 {
|
||||
l.size--
|
||||
|
||||
temp := l.head.next
|
||||
hnext := temp.next
|
||||
hnext.prev = l.head
|
||||
l.head.next = hnext
|
||||
|
||||
result = temp.value
|
||||
found = true
|
||||
return
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) PopBack() (result interface{}, found bool) {
|
||||
if l.size != 0 {
|
||||
l.size--
|
||||
|
||||
temp := l.tail.prev
|
||||
tprev := temp.prev
|
||||
tprev.next = l.tail
|
||||
l.tail.prev = tprev
|
||||
|
||||
result = temp.value
|
||||
found = true
|
||||
return
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) Front() (result interface{}, found bool) {
|
||||
if l.size != 0 {
|
||||
return l.head.next.value, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) Back() (result interface{}, found bool) {
|
||||
if l.size != 0 {
|
||||
return l.tail.prev.value, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) Find(every func(idx uint, value interface{}) bool) (interface{}, bool) {
|
||||
|
||||
idx := uint(0)
|
||||
// 头部
|
||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||
if every(idx, cur.value) {
|
||||
return cur.value, true
|
||||
}
|
||||
idx++
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) FindMany(every func(idx uint, value interface{}) int) (result []interface{}, isfound bool) {
|
||||
// the default of isfould is false
|
||||
idx := uint(0)
|
||||
// 头部
|
||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||
j := every(idx, cur.value)
|
||||
switch {
|
||||
case j > 0:
|
||||
result = append(result, cur.value)
|
||||
isfound = true
|
||||
case j < 0:
|
||||
return result, isfound
|
||||
}
|
||||
idx++
|
||||
}
|
||||
return result, isfound
|
||||
}
|
||||
|
||||
func (l *LinkedList) Index(idx uint) (interface{}, bool) {
|
||||
if idx >= l.size {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if idx > l.size/2 {
|
||||
idx = l.size - 1 - idx
|
||||
// 尾部
|
||||
for cur := l.tail.prev; cur != l.head; cur = cur.prev {
|
||||
if idx == 0 {
|
||||
return cur.value, true
|
||||
}
|
||||
idx--
|
||||
}
|
||||
|
||||
} else {
|
||||
// 头部
|
||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||
if idx == 0 {
|
||||
return cur.value, true
|
||||
}
|
||||
idx--
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (l *LinkedList) Insert(idx uint, values ...interface{}) {
|
||||
if idx > l.size { // 插入的方式 可能导致size的范围判断不一样
|
||||
return
|
||||
}
|
||||
|
||||
if idx > l.size/2 {
|
||||
idx = l.size - idx
|
||||
// 尾部
|
||||
for cur := l.tail.prev; cur != nil; cur = cur.prev {
|
||||
|
||||
if idx == 0 {
|
||||
|
||||
var start *Node
|
||||
var end *Node
|
||||
|
||||
start = &Node{value: values[0]}
|
||||
end = start
|
||||
|
||||
for _, value := range values[1:] {
|
||||
node := &Node{value: value}
|
||||
end.next = node
|
||||
node.prev = end
|
||||
end = node
|
||||
}
|
||||
|
||||
cnext := cur.next
|
||||
|
||||
cur.next = start
|
||||
start.prev = cur
|
||||
|
||||
end.next = cnext
|
||||
cnext.prev = end
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
idx--
|
||||
}
|
||||
|
||||
} else {
|
||||
// 头部
|
||||
for cur := l.head.next; cur != nil; cur = cur.next {
|
||||
if idx == 0 {
|
||||
|
||||
var start *Node
|
||||
var end *Node
|
||||
|
||||
start = &Node{value: values[0]}
|
||||
end = start
|
||||
|
||||
for _, value := range values[1:] {
|
||||
node := &Node{value: value}
|
||||
end.next = node
|
||||
node.prev = end
|
||||
end = node
|
||||
}
|
||||
|
||||
cprev := cur.prev
|
||||
|
||||
cprev.next = start
|
||||
start.prev = cprev
|
||||
|
||||
end.next = cur
|
||||
cur.prev = end
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
idx--
|
||||
}
|
||||
}
|
||||
|
||||
l.size += uint(len(values))
|
||||
}
|
||||
|
||||
// InsertState InsertIf的every函数的枚举 从左到右 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
|
||||
// UninsertAndContinue 不插入并且继续
|
||||
// UninsertAndBreak 不插入并且停止
|
||||
// InsertBack cur后插入并且停止
|
||||
// InsertFront cur前插入并且停止
|
||||
type InsertState int
|
||||
|
||||
const (
|
||||
// UninsertAndContinue 不插入并且继续
|
||||
UninsertAndContinue InsertState = 0
|
||||
// UninsertAndBreak 不插入并且停止
|
||||
UninsertAndBreak InsertState = -1
|
||||
// InsertBack cur后插入并且停止
|
||||
InsertBack InsertState = 2
|
||||
// InsertFront cur前插入并且停止
|
||||
InsertFront InsertState = 1
|
||||
)
|
||||
|
||||
// InsertIf every函数的枚举 从左到右遍历 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
|
||||
func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) InsertState, values ...interface{}) {
|
||||
|
||||
idx := uint(0)
|
||||
// 头部
|
||||
for cur := l.head.next; cur != nil; cur = cur.next {
|
||||
insertState := every(idx, cur.value)
|
||||
|
||||
if insertState == UninsertAndContinue {
|
||||
continue
|
||||
}
|
||||
|
||||
if insertState > 0 { // 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
|
||||
var start *Node
|
||||
var end *Node
|
||||
|
||||
start = &Node{value: values[0]}
|
||||
end = start
|
||||
|
||||
for _, value := range values[1:] {
|
||||
node := &Node{value: value}
|
||||
end.next = node
|
||||
node.prev = end
|
||||
end = node
|
||||
}
|
||||
|
||||
if insertState == InsertBack {
|
||||
cprev := cur.prev
|
||||
cprev.next = start
|
||||
start.prev = cprev
|
||||
end.next = cur
|
||||
cur.prev = end
|
||||
} else { // InsertFront
|
||||
cnext := cur.next
|
||||
cnext.prev = end
|
||||
start.prev = cur
|
||||
cur.next = start
|
||||
end.next = cnext
|
||||
}
|
||||
|
||||
l.size += uint(len(values))
|
||||
return
|
||||
}
|
||||
|
||||
// 必然 等于 UninsertAndBreak
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func remove(cur *Node) {
|
||||
curPrev := cur.prev
|
||||
curNext := cur.next
|
||||
curPrev.next = curNext
|
||||
curNext.prev = curPrev
|
||||
cur.prev = nil
|
||||
cur.next = nil
|
||||
}
|
||||
|
||||
func (l *LinkedList) Remove(idx uint) (interface{}, bool) {
|
||||
if l.size <= idx {
|
||||
log.Printf("out of list range, size is %d, idx is %d\n", l.size, idx)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
l.size--
|
||||
if idx > l.size/2 {
|
||||
idx = l.size - idx // l.size - 1 - idx, 先减size
|
||||
// 尾部
|
||||
for cur := l.tail.prev; cur != l.head; cur = cur.prev {
|
||||
if idx == 0 {
|
||||
remove(cur)
|
||||
return cur.value, true
|
||||
}
|
||||
idx--
|
||||
}
|
||||
|
||||
} else {
|
||||
// 头部
|
||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||
if idx == 0 {
|
||||
remove(cur)
|
||||
return cur.value, true
|
||||
|
||||
}
|
||||
idx--
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("unknown error"))
|
||||
}
|
||||
|
||||
// RemoveState RemoveIf的every函数的枚举
|
||||
// RemoveAndContinue 删除并且继续
|
||||
// RemoveAndBreak 删除并且停止
|
||||
// UnremoveAndBreak 不删除并且停止遍历
|
||||
// UnremoveAndContinue 不删除并且继续遍历
|
||||
type RemoveState int
|
||||
|
||||
const (
|
||||
// RemoveAndContinue 删除并且继续
|
||||
RemoveAndContinue RemoveState = iota
|
||||
// RemoveAndBreak 删除并且停止
|
||||
RemoveAndBreak
|
||||
// UnremoveAndBreak 不删除并且停止遍历
|
||||
UnremoveAndBreak
|
||||
// UnremoveAndContinue 不删除并且继续遍历
|
||||
UnremoveAndContinue
|
||||
)
|
||||
|
||||
// RemoveIf every的遍历函数操作remove过程 如果没删除result 返回nil, isRemoved = false
|
||||
func (l *LinkedList) RemoveIf(every func(idx uint, value interface{}) RemoveState) (result []interface{}, isRemoved bool) {
|
||||
// 头部
|
||||
idx := uint(0)
|
||||
TOPFOR:
|
||||
for cur := l.head.next; cur != l.tail; idx++ {
|
||||
removeState := every(idx, cur.value)
|
||||
switch removeState {
|
||||
case RemoveAndContinue:
|
||||
result = append(result, cur.value)
|
||||
isRemoved = true
|
||||
temp := cur.next
|
||||
remove(cur)
|
||||
cur = temp
|
||||
l.size--
|
||||
continue TOPFOR
|
||||
case RemoveAndBreak:
|
||||
result = append(result, cur.value)
|
||||
isRemoved = true
|
||||
temp := cur.next
|
||||
remove(cur)
|
||||
cur = temp
|
||||
l.size--
|
||||
return
|
||||
case UnremoveAndContinue:
|
||||
case UnremoveAndBreak:
|
||||
return
|
||||
}
|
||||
|
||||
cur = cur.next
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (l *LinkedList) Values() (result []interface{}) {
|
||||
l.Traversal(func(value interface{}) bool {
|
||||
result = append(result, value)
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (l *LinkedList) String() string {
|
||||
return spew.Sprint(l.Values())
|
||||
}
|
||||
|
||||
func (l *LinkedList) Traversal(every func(interface{}) bool) {
|
||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||
if !every(cur.value) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
664
list/linked_list/linked_list_test.go
Normal file
664
list/linked_list/linked_list_test.go
Normal file
@@ -0,0 +1,664 @@
|
||||
package linkedlist
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Pallinder/go-randomdata"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
func TestPushFront(t *testing.T) {
|
||||
l := New()
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
var result string
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[4 3 2 1 0]" {
|
||||
t.Error(result)
|
||||
}
|
||||
|
||||
l.PushFront(0)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[0 4 3 2 1 0]" {
|
||||
t.Error(result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushBack(t *testing.T) {
|
||||
l := New()
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushBack(i)
|
||||
}
|
||||
var result string
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[0 1 2 3 4]" {
|
||||
t.Error(result)
|
||||
}
|
||||
|
||||
l.PushBack(0)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[0 1 2 3 4 0]" {
|
||||
t.Error(result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPopFront(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
// var result string
|
||||
|
||||
for i := 4; i >= 0; i-- {
|
||||
if v, ok := l.PopFront(); ok {
|
||||
if v != i {
|
||||
t.Error("[4 3 2 1 0] PopFront value should be ", i, ", but is ", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("PopFront is not ok")
|
||||
}
|
||||
|
||||
if l.Size() != uint(i) {
|
||||
t.Error("l.Size() is error, is", l.Size())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPopBack(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
// var result string
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
if v, ok := l.PopBack(); ok {
|
||||
if v != i {
|
||||
t.Error("[4 3 2 1 0] PopFront value should be ", i, ", but is ", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("PopFront is not ok")
|
||||
}
|
||||
|
||||
if l.Size() != uint(5-i-1) {
|
||||
t.Error("l.Size() is error, is", l.Size())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestInsert2(t *testing.T) {
|
||||
l := New()
|
||||
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(0, i)
|
||||
}
|
||||
|
||||
// step1: [0 0] -> step2: [1 0 0 0] front
|
||||
if l.String() != "[4 0 3 0 2 0 1 0 0 0]" {
|
||||
t.Error(l.String())
|
||||
}
|
||||
|
||||
l.Insert(l.Size(), 5)
|
||||
|
||||
// step1: [0 0] -> step2: [4 0 3 0 2 0 1 0 0 0] front size is 10, but you can insert 11. equal to PushBack [4 0 3 0 2 0 1 0 0 0 5]
|
||||
if l.String() != "[4 0 3 0 2 0 1 0 0 0 5]" {
|
||||
t.Error(l.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsert1(t *testing.T) {
|
||||
l1 := New()
|
||||
l2 := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l1.Insert(0, i)
|
||||
l2.PushFront(i)
|
||||
}
|
||||
|
||||
var result1, result2 string
|
||||
result1 = spew.Sprint(l1.Values())
|
||||
result2 = spew.Sprint(l2.Values())
|
||||
if result1 != result2 {
|
||||
t.Error(result1, result2)
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
l1.Insert(l1.Size(), i)
|
||||
l2.PushBack(i)
|
||||
// t.Error(l1.Values(), l2.Values())
|
||||
}
|
||||
|
||||
result1 = spew.Sprint(l1.Values())
|
||||
result2 = spew.Sprint(l2.Values())
|
||||
if result1 != result2 {
|
||||
t.Error(result1, result2)
|
||||
}
|
||||
|
||||
if result1 != "[4 3 2 1 0 0 1 2 3 4]" {
|
||||
t.Error("result should be [4 3 2 1 0 0 1 2 3 4]\n but result is", result1)
|
||||
}
|
||||
|
||||
l1.Insert(1, 99)
|
||||
result1 = spew.Sprint(l1.Values())
|
||||
if result1 != "[4 99 3 2 1 0 0 1 2 3 4]" {
|
||||
t.Error("[4 3 2 1 0 0 1 2 3 4] insert with index 1, should be [4 99 3 2 1 0 0 1 2 3 4]\n but result is", result1)
|
||||
}
|
||||
|
||||
l1.Insert(9, 99)
|
||||
result1 = spew.Sprint(l1.Values())
|
||||
if result1 != "[4 99 3 2 1 0 0 1 2 99 3 4]" {
|
||||
t.Error("[4 99 3 2 1 0 0 1 2 3 4] insert with index 9, should be [4 99 3 2 1 0 0 1 2 99 3 4]\n but result is", result1)
|
||||
}
|
||||
|
||||
l1.Insert(12, 99)
|
||||
result1 = spew.Sprint(l1.Values())
|
||||
if result1 != "[4 99 3 2 1 0 0 1 2 99 3 4 99]" {
|
||||
t.Error("[4 99 3 2 1 0 0 1 2 99 3 4] insert with index 12, should be [4 99 3 2 1 0 0 1 2 99 3 4 99]\n but result is", result1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertIf(t *testing.T) {
|
||||
l := New()
|
||||
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.Insert(0, i)
|
||||
}
|
||||
|
||||
// "[4 3 2 1 0]" 插入两个11
|
||||
for i := 0; i < 2; i++ {
|
||||
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||
if value == 3 {
|
||||
return InsertFront
|
||||
}
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
var result string
|
||||
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[4 3 11 11 2 1 0]" {
|
||||
t.Error("result should be [4 3 11 11 2 1 0], reuslt is", result)
|
||||
}
|
||||
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 2; i++ {
|
||||
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||
if value == 0 {
|
||||
return InsertBack
|
||||
}
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[4 3 11 11 2 1 11 11 0]" {
|
||||
t.Error("result should be [4 3 11 11 2 1 11 11 0], reuslt is", result)
|
||||
}
|
||||
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 2; i++ {
|
||||
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||
if value == 0 {
|
||||
return InsertFront
|
||||
}
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[4 3 11 11 2 1 11 11 0 11 11]" {
|
||||
t.Error("result should be [4 3 11 11 2 1 11 11 0 11 11], reuslt is", result)
|
||||
}
|
||||
|
||||
// t.Error(l.Values())
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
if v, isfound := l.Find(func(idx uint, value interface{}) bool {
|
||||
if idx == 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}); isfound {
|
||||
if v != 3 {
|
||||
t.Error("[4 3 2 1 0] index 1 shoud be 3 but value is", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be found")
|
||||
}
|
||||
|
||||
if v, isfound := l.Find(func(idx uint, value interface{}) bool {
|
||||
if idx == 5 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}); isfound {
|
||||
t.Error("should not be found, but v is found, ", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindMany(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
if values, isfound := l.FindMany(func(idx uint, value interface{}) int {
|
||||
if idx >= 1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}); isfound {
|
||||
var result string
|
||||
result = spew.Sprint(values)
|
||||
if result != "[3 2 1 0]" {
|
||||
t.Error("result should be [3 2 1 0], reuslt is", result)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be found")
|
||||
}
|
||||
|
||||
if values, isfound := l.FindMany(func(idx uint, value interface{}) int {
|
||||
if idx%2 == 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}); isfound {
|
||||
var result string
|
||||
result = spew.Sprint(values)
|
||||
if result != "[4 2 0]" {
|
||||
t.Error("result should be [3 2 1 0], reuslt is", result)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be found")
|
||||
}
|
||||
|
||||
if values, isfound := l.FindMany(func(idx uint, value interface{}) int {
|
||||
if value == 0 || value == 2 || value == 4 || value == 7 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}); isfound {
|
||||
var result string
|
||||
result = spew.Sprint(values)
|
||||
if result != "[4 2 0]" {
|
||||
t.Error("result should be [4 2 0], reuslt is", result)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be found")
|
||||
}
|
||||
|
||||
if values, isfound := l.FindMany(func(idx uint, value interface{}) int {
|
||||
if value.(int) <= 2 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if value.(int) <= 4 && value.(int) > 2 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}); isfound {
|
||||
var result string
|
||||
result = spew.Sprint(values)
|
||||
if result != "[4 3]" {
|
||||
t.Error("result should be [4 2 0], reuslt is", result)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be found")
|
||||
}
|
||||
// if v, isfound := l.Find(func(idx uint, value interface{}) bool {
|
||||
// if idx == 5 {
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }); isfound {
|
||||
// t.Error("should not be found, but v is found, ", v)
|
||||
// }
|
||||
}
|
||||
|
||||
func TestIndex(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
if v, ok := l.Index(4); ok {
|
||||
if v != 0 {
|
||||
t.Error("[4 3 2 1 0] Index 4 value is 0, but v is ", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("not ok is error")
|
||||
}
|
||||
|
||||
if v, ok := l.Index(1); ok {
|
||||
if v != 3 {
|
||||
t.Error("[4 3 2 1 0] Index 1 value is 3, but v is ", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("not ok is error")
|
||||
}
|
||||
|
||||
if v, ok := l.Index(0); ok {
|
||||
if v != 4 {
|
||||
t.Error("[4 3 2 1 0] Index 1 value is 4, but v is ", v)
|
||||
}
|
||||
} else {
|
||||
t.Error("not ok is error")
|
||||
}
|
||||
|
||||
if _, ok := l.Index(5); ok {
|
||||
t.Error("[4 3 2 1 0] Index 5, out of range,ok = true is error")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
l.Remove(0)
|
||||
var result string
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3 2 1 0]" {
|
||||
t.Error("should be [3 2 1 0] but result is", result)
|
||||
}
|
||||
|
||||
l.Remove(3)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3 2 1]" {
|
||||
t.Error("should be [3 2 1] but result is", result)
|
||||
}
|
||||
|
||||
l.Remove(2)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3 2]" {
|
||||
t.Error("should be [3 2 1] but result is", result)
|
||||
}
|
||||
|
||||
l.Remove(1)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3]" {
|
||||
t.Error("should be [3 2 1] but result is", result)
|
||||
}
|
||||
|
||||
l.Remove(0)
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "<nil>" && l.Size() == 0 && len(l.Values()) == 0 {
|
||||
t.Error("should be [3 2 1] but result is", result, "Size is", l.Size())
|
||||
}
|
||||
|
||||
if _, rvalue := l.Remove(3); rvalue != false {
|
||||
t.Error("l is empty")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRemoveIf(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 0 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
if result[0] != 0 {
|
||||
t.Error("result should is", 0)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be ok")
|
||||
}
|
||||
|
||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 4 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
if result[0] != 4 {
|
||||
t.Error("result should is", 4)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be ok")
|
||||
}
|
||||
|
||||
var result string
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3 2 1]" {
|
||||
t.Error("should be [3 2 1] but result is", result)
|
||||
}
|
||||
|
||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 4 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
t.Error("should not be ok and result is nil")
|
||||
} else {
|
||||
if result != nil {
|
||||
t.Error("should be nil")
|
||||
}
|
||||
}
|
||||
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "[3 2 1]" {
|
||||
t.Error("should be [3 2 1] but result is", result)
|
||||
}
|
||||
|
||||
l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 3 || value == 2 || value == 1 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
})
|
||||
|
||||
result = spew.Sprint(l.Values())
|
||||
if result != "<nil>" {
|
||||
t.Error("result should be <nil>, but now result is", result)
|
||||
}
|
||||
|
||||
if results, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 3 || value == 2 || value == 1 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
t.Error("why ok")
|
||||
} else {
|
||||
if results != nil {
|
||||
t.Error(results)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestRemoveIf2(t *testing.T) {
|
||||
l := New()
|
||||
// "[4 3 2 1 0]"
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
|
||||
// 只删除一个
|
||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 0 {
|
||||
return RemoveAndBreak
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
if result[0] != 0 {
|
||||
t.Error("result should is", 0)
|
||||
}
|
||||
} else {
|
||||
t.Error("should be ok")
|
||||
}
|
||||
|
||||
var resultstr string
|
||||
resultstr = spew.Sprint(l.Values())
|
||||
if resultstr != "[4 3 2 1 4 3 2 1 0]" {
|
||||
t.Error("result should is", resultstr)
|
||||
}
|
||||
|
||||
// 只删除多个
|
||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||
if value == 4 {
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
|
||||
resultstr = spew.Sprint(result)
|
||||
if resultstr != "[4 4]" {
|
||||
t.Error("result should is", result)
|
||||
}
|
||||
|
||||
resultstr = spew.Sprint(l.Values())
|
||||
if resultstr != "[3 2 1 3 2 1 0]" {
|
||||
t.Error("result should is", resultstr)
|
||||
}
|
||||
|
||||
} else {
|
||||
t.Error("should be ok")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterator(t *testing.T) {
|
||||
ll := New()
|
||||
for i := 0; i < 10; i++ {
|
||||
ll.PushFront(i)
|
||||
}
|
||||
|
||||
iter := ll.Iterator()
|
||||
|
||||
for i := 0; iter.Next(); i++ {
|
||||
if iter.Value() != 9-i {
|
||||
t.Error("iter.Next() ", iter.Value(), "is not equal ", 9-i)
|
||||
}
|
||||
}
|
||||
|
||||
if iter.cur != iter.ll.tail {
|
||||
t.Error("current point is not equal tail ", iter.ll.tail)
|
||||
}
|
||||
|
||||
for i := 0; iter.Prev(); i++ {
|
||||
if iter.Value() != i {
|
||||
t.Error("iter.Prev() ", iter.Value(), "is not equal ", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCircularIterator(t *testing.T) {
|
||||
ll := New()
|
||||
for i := 0; i < 10; i++ {
|
||||
ll.PushFront(i)
|
||||
}
|
||||
|
||||
iter := ll.CircularIterator()
|
||||
|
||||
for i := 0; i != 10; i++ {
|
||||
iter.Next()
|
||||
if iter.Value() != 9-i {
|
||||
t.Error("iter.Next() ", iter.Value(), "is not equal ", 9-i)
|
||||
}
|
||||
}
|
||||
|
||||
if iter.cur != iter.pl.tail.prev {
|
||||
t.Error("current point is not equal tail ", iter.pl.tail.prev)
|
||||
}
|
||||
|
||||
if iter.Next() {
|
||||
if iter.Value() != 9 {
|
||||
t.Error("iter.Value() != ", iter.Value())
|
||||
}
|
||||
}
|
||||
|
||||
iter.MoveToTail()
|
||||
for i := 0; i != 10; i++ {
|
||||
iter.Prev()
|
||||
if iter.Value() != i {
|
||||
t.Error("iter.Prev() ", iter.Value(), "is not equal ", i)
|
||||
}
|
||||
}
|
||||
|
||||
if iter.cur != iter.pl.head.next {
|
||||
t.Error("current point is not equal tail ", iter.pl.tail.prev)
|
||||
}
|
||||
|
||||
if iter.Prev() {
|
||||
if iter.Value() != 0 {
|
||||
t.Error("iter.Value() != ", iter.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPushBack(b *testing.B) {
|
||||
|
||||
ec := 5
|
||||
cs := 2000000
|
||||
b.N = cs * ec
|
||||
|
||||
for c := 0; c < ec; c++ {
|
||||
l := New()
|
||||
for i := 0; i < cs; i++ {
|
||||
l.PushBack(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPushFront(b *testing.B) {
|
||||
|
||||
ec := 5
|
||||
cs := 2000000
|
||||
b.N = cs * ec
|
||||
|
||||
for c := 0; c < ec; c++ {
|
||||
l := New()
|
||||
for i := 0; i < cs; i++ {
|
||||
l.PushFront(i)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkInsert(b *testing.B) {
|
||||
|
||||
ec := 10
|
||||
cs := 1000
|
||||
b.N = cs * ec
|
||||
|
||||
for c := 0; c < ec; c++ {
|
||||
l := New()
|
||||
for i := 0; i < cs; i++ {
|
||||
ridx := randomdata.Number(0, int(l.Size())+1)
|
||||
l.Insert(uint(ridx), i)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user