Merge branch 'feature/LinkedHashmap' into develop
This commit is contained in:
commit
1a4afeb4b5
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
|
||||||
|
}
|
|
@ -1,6 +1,10 @@
|
||||||
package linkedlist
|
package linkedlist
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
prev *Node
|
prev *Node
|
||||||
|
@ -18,12 +22,6 @@ type LinkedList struct {
|
||||||
size uint
|
size uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// var nodePool *sync.Pool = &sync.Pool{
|
|
||||||
// New: func() interface{} {
|
|
||||||
// return &Node{}
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
|
|
||||||
func New() *LinkedList {
|
func New() *LinkedList {
|
||||||
l := &LinkedList{}
|
l := &LinkedList{}
|
||||||
l.head = &Node{}
|
l.head = &Node{}
|
||||||
|
@ -37,6 +35,14 @@ func New() *LinkedList {
|
||||||
return l
|
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() {
|
func (l *LinkedList) Clear() {
|
||||||
l.head.next = nil
|
l.head.next = nil
|
||||||
l.tail.prev = nil
|
l.tail.prev = nil
|
||||||
|
@ -190,9 +196,9 @@ func (l *LinkedList) Index(idx uint) (interface{}, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LinkedList) Insert(idx uint, values ...interface{}) {
|
func (l *LinkedList) Insert(idx uint, values ...interface{}) bool {
|
||||||
if idx > l.size {
|
if idx > l.size { // 插入的方式 可能导致size的范围判断不一样
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx > l.size/2 {
|
if idx > l.size/2 {
|
||||||
|
@ -263,15 +269,40 @@ func (l *LinkedList) Insert(idx uint, values ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
l.size += uint(len(values))
|
l.size += uint(len(values))
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) int, values ...interface{}) {
|
// 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)
|
idx := uint(0)
|
||||||
// 头部
|
// 头部
|
||||||
for cur := l.head.next; cur != nil; cur = cur.next {
|
for cur := l.head.next; cur != nil; cur = cur.next {
|
||||||
isInsert := every(idx, cur.value)
|
insertState := every(idx, cur.value)
|
||||||
if isInsert != 0 { // 1 为前 -1 为后 insert here(-1) ->cur-> insert here(1)
|
|
||||||
|
if insertState == UninsertAndContinue {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if insertState > 0 { // 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
|
||||||
var start *Node
|
var start *Node
|
||||||
var end *Node
|
var end *Node
|
||||||
|
|
||||||
|
@ -285,13 +316,13 @@ func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) int, value
|
||||||
end = node
|
end = node
|
||||||
}
|
}
|
||||||
|
|
||||||
if isInsert < 0 {
|
if insertState == InsertBack {
|
||||||
cprev := cur.prev
|
cprev := cur.prev
|
||||||
cprev.next = start
|
cprev.next = start
|
||||||
start.prev = cprev
|
start.prev = cprev
|
||||||
end.next = cur
|
end.next = cur
|
||||||
cur.prev = end
|
cur.prev = end
|
||||||
} else {
|
} else { // InsertFront
|
||||||
cnext := cur.next
|
cnext := cur.next
|
||||||
cnext.prev = end
|
cnext.prev = end
|
||||||
start.prev = cur
|
start.prev = cur
|
||||||
|
@ -300,8 +331,11 @@ func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) int, value
|
||||||
}
|
}
|
||||||
|
|
||||||
l.size += uint(len(values))
|
l.size += uint(len(values))
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 必然 等于 UninsertAndBreak
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +349,9 @@ func remove(cur *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LinkedList) Remove(idx uint) (interface{}, bool) {
|
func (l *LinkedList) Remove(idx uint) (interface{}, bool) {
|
||||||
if idx >= l.size {
|
if l.size <= idx {
|
||||||
panic(fmt.Sprintf("out of list range, size is %d, idx is %d", l.size, idx))
|
// log.Printf("out of list range, size is %d, idx is %d\n", l.size, idx)
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
l.size--
|
l.size--
|
||||||
|
@ -346,21 +381,50 @@ func (l *LinkedList) Remove(idx uint) (interface{}, bool) {
|
||||||
panic(fmt.Sprintf("unknown error"))
|
panic(fmt.Sprintf("unknown error"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LinkedList) RemoveIf(every func(idx uint, value interface{}) int) (result []interface{}, isRemoved bool) {
|
// 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)
|
idx := uint(0)
|
||||||
|
TOPFOR:
|
||||||
for cur := l.head.next; cur != l.tail; idx++ {
|
for cur := l.head.next; cur != l.tail; idx++ {
|
||||||
j := every(idx, cur.value)
|
removeState := every(idx, cur.value)
|
||||||
switch {
|
switch removeState {
|
||||||
case j > 0:
|
case RemoveAndContinue:
|
||||||
result = append(result, cur.value)
|
result = append(result, cur.value)
|
||||||
isRemoved = true
|
isRemoved = true
|
||||||
temp := cur.next
|
temp := cur.next
|
||||||
remove(cur)
|
remove(cur)
|
||||||
cur = temp
|
cur = temp
|
||||||
l.size--
|
l.size--
|
||||||
continue
|
continue TOPFOR
|
||||||
case j < 0:
|
case RemoveAndBreak:
|
||||||
|
result = append(result, cur.value)
|
||||||
|
isRemoved = true
|
||||||
|
temp := cur.next
|
||||||
|
remove(cur)
|
||||||
|
cur = temp
|
||||||
|
l.size--
|
||||||
|
return
|
||||||
|
case UnremoveAndContinue:
|
||||||
|
case UnremoveAndBreak:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +441,10 @@ func (l *LinkedList) Values() (result []interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LinkedList) String() string {
|
||||||
|
return spew.Sprint(l.Values())
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LinkedList) Traversal(every func(interface{}) bool) {
|
func (l *LinkedList) Traversal(every func(interface{}) bool) {
|
||||||
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
for cur := l.head.next; cur != l.tail; cur = cur.next {
|
||||||
if !every(cur.value) {
|
if !every(cur.value) {
|
|
@ -90,7 +90,30 @@ func TestPopBack(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsert(t *testing.T) {
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !l.Insert(l.Size(), 5) {
|
||||||
|
t.Error("should be true")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
l1 := New()
|
||||||
l2 := New()
|
l2 := New()
|
||||||
// "[4 3 2 1 0]"
|
// "[4 3 2 1 0]"
|
||||||
|
@ -149,13 +172,13 @@ func TestInsertIf(t *testing.T) {
|
||||||
l.Insert(0, i)
|
l.Insert(0, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// "[4 3 2 1 0]"
|
// "[4 3 2 1 0]" 插入两个11
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
l.InsertIf(func(idx uint, value interface{}) int {
|
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||||
if value == 3 {
|
if value == 3 {
|
||||||
return 1
|
return InsertFront
|
||||||
}
|
}
|
||||||
return 0
|
return UninsertAndContinue
|
||||||
}, 11)
|
}, 11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,11 +191,11 @@ func TestInsertIf(t *testing.T) {
|
||||||
|
|
||||||
// "[4 3 2 1 0]"
|
// "[4 3 2 1 0]"
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
l.InsertIf(func(idx uint, value interface{}) int {
|
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
return -1
|
return InsertBack
|
||||||
}
|
}
|
||||||
return 0
|
return UninsertAndContinue
|
||||||
}, 11)
|
}, 11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,11 +206,11 @@ func TestInsertIf(t *testing.T) {
|
||||||
|
|
||||||
// "[4 3 2 1 0]"
|
// "[4 3 2 1 0]"
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
l.InsertIf(func(idx uint, value interface{}) int {
|
l.InsertIf(func(idx uint, value interface{}) InsertState {
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
return 1
|
return InsertFront
|
||||||
}
|
}
|
||||||
return 0
|
return UninsertAndContinue
|
||||||
}, 11)
|
}, 11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,13 +408,10 @@ func TestRemove(t *testing.T) {
|
||||||
t.Error("should be [3 2 1] but result is", result, "Size is", l.Size())
|
t.Error("should be [3 2 1] but result is", result, "Size is", l.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
if _, rvalue := l.Remove(3); rvalue != false {
|
||||||
if err := recover(); err == nil {
|
t.Error("l is empty")
|
||||||
t.Error("should be out of range but is not")
|
}
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
l.Remove(3)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveIf(t *testing.T) {
|
func TestRemoveIf(t *testing.T) {
|
||||||
|
@ -401,11 +421,11 @@ func TestRemoveIf(t *testing.T) {
|
||||||
l.PushFront(i)
|
l.PushFront(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) int {
|
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||||
if value == 0 {
|
if value == 0 {
|
||||||
return 1
|
return RemoveAndContinue
|
||||||
}
|
}
|
||||||
return 0
|
return UnremoveAndContinue
|
||||||
}); ok {
|
}); ok {
|
||||||
if result[0] != 0 {
|
if result[0] != 0 {
|
||||||
t.Error("result should is", 0)
|
t.Error("result should is", 0)
|
||||||
|
@ -414,11 +434,11 @@ func TestRemoveIf(t *testing.T) {
|
||||||
t.Error("should be ok")
|
t.Error("should be ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) int {
|
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||||
if value == 4 {
|
if value == 4 {
|
||||||
return 1
|
return RemoveAndContinue
|
||||||
}
|
}
|
||||||
return 0
|
return UnremoveAndContinue
|
||||||
}); ok {
|
}); ok {
|
||||||
if result[0] != 4 {
|
if result[0] != 4 {
|
||||||
t.Error("result should is", 4)
|
t.Error("result should is", 4)
|
||||||
|
@ -433,11 +453,11 @@ func TestRemoveIf(t *testing.T) {
|
||||||
t.Error("should be [3 2 1] but result is", result)
|
t.Error("should be [3 2 1] but result is", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
if result, ok := l.RemoveIf(func(idx uint, value interface{}) int {
|
if result, ok := l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||||
if value == 4 {
|
if value == 4 {
|
||||||
return 1
|
return RemoveAndContinue
|
||||||
}
|
}
|
||||||
return 0
|
return UnremoveAndContinue
|
||||||
}); ok {
|
}); ok {
|
||||||
t.Error("should not be ok and result is nil")
|
t.Error("should not be ok and result is nil")
|
||||||
} else {
|
} else {
|
||||||
|
@ -451,17 +471,154 @@ func TestRemoveIf(t *testing.T) {
|
||||||
t.Error("should be [3 2 1] but result is", result)
|
t.Error("should be [3 2 1] but result is", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
l.RemoveIf(func(idx uint, value interface{}) int {
|
l.RemoveIf(func(idx uint, value interface{}) RemoveState {
|
||||||
if value == 3 || value == 2 || value == 1 {
|
if value == 3 || value == 2 || value == 1 {
|
||||||
return 1
|
return RemoveAndContinue
|
||||||
}
|
}
|
||||||
return 0
|
return UnremoveAndContinue
|
||||||
})
|
})
|
||||||
|
|
||||||
result = spew.Sprint(l.Values())
|
result = spew.Sprint(l.Values())
|
||||||
if result != "<nil>" {
|
if result != "<nil>" {
|
||||||
t.Error("result should be <nil>, but now result is", result)
|
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) {
|
func BenchmarkPushBack(b *testing.B) {
|
129
map/linked_hashmap/linked_hashmap.go
Normal file
129
map/linked_hashmap/linked_hashmap.go
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package linkedhashmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
linkedlist "github.com/474420502/focus/list/linked_list"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LinkedHashmap
|
||||||
|
type LinkedHashmap struct {
|
||||||
|
list *linkedlist.LinkedList
|
||||||
|
hmap map[interface{}]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New
|
||||||
|
func New() *LinkedHashmap {
|
||||||
|
lhmap := &LinkedHashmap{list: linkedlist.New(), hmap: make(map[interface{}]interface{})}
|
||||||
|
return lhmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put equal to PushBack
|
||||||
|
func (lhmap *LinkedHashmap) Put(key interface{}, value interface{}) {
|
||||||
|
if _, ok := lhmap.hmap[key]; !ok {
|
||||||
|
lhmap.list.PushBack(key)
|
||||||
|
}
|
||||||
|
lhmap.hmap[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushBack equal to Put, if key exists, push value replace the value is exists. size is unchanging
|
||||||
|
func (lhmap *LinkedHashmap) PushBack(key interface{}, value interface{}) {
|
||||||
|
if _, ok := lhmap.hmap[key]; !ok {
|
||||||
|
lhmap.list.PushBack(key)
|
||||||
|
}
|
||||||
|
lhmap.hmap[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFront if key exists, push value replace the value is exists. size is unchanging
|
||||||
|
func (lhmap *LinkedHashmap) PushFront(key interface{}, value interface{}) {
|
||||||
|
if _, ok := lhmap.hmap[key]; !ok {
|
||||||
|
lhmap.list.PushFront(key)
|
||||||
|
}
|
||||||
|
lhmap.hmap[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 如果成功在该位置返回True, 否则返回false 类似 linkedlist Size 可以 等于 idx
|
||||||
|
func (lhmap *LinkedHashmap) Insert(idx uint, key interface{}, value interface{}) bool {
|
||||||
|
if _, ok := lhmap.hmap[key]; !ok {
|
||||||
|
lhmap.list.Insert(idx, key)
|
||||||
|
lhmap.hmap[key] = value
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get
|
||||||
|
func (lhmap *LinkedHashmap) Get(key interface{}) (interface{}, bool) {
|
||||||
|
value, ok := lhmap.hmap[key]
|
||||||
|
return value, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
func (lhmap *LinkedHashmap) Clear() {
|
||||||
|
lhmap.list.Clear()
|
||||||
|
lhmap.hmap = make(map[interface{}]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove if key not exists reture nil, false.
|
||||||
|
func (lhmap *LinkedHashmap) Remove(key interface{}) (interface{}, bool) {
|
||||||
|
if v, ok := lhmap.hmap[key]; ok {
|
||||||
|
delete(lhmap.hmap, key)
|
||||||
|
lhmap.list.RemoveIf(func(idx uint, lkey interface{}) linkedlist.RemoveState {
|
||||||
|
if lkey == key {
|
||||||
|
return linkedlist.RemoveAndBreak
|
||||||
|
}
|
||||||
|
return linkedlist.UnremoveAndContinue
|
||||||
|
})
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveIndex
|
||||||
|
func (lhmap *LinkedHashmap) RemoveIndex(idx uint) (interface{}, bool) {
|
||||||
|
if lhmap.list.Size() >= idx {
|
||||||
|
// log.Printf("warn: out of list range, size is %d, idx is %d\n", lhmap.list.Size(), idx)
|
||||||
|
if key, ok := lhmap.list.Remove(idx); ok {
|
||||||
|
result := lhmap.hmap[key]
|
||||||
|
delete(lhmap.hmap, key)
|
||||||
|
return result, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveIf 不是必须不实现这个
|
||||||
|
// func (lhmap *LinkedHashmap) RemoveIf(every func(idx uint, key interface{}) RemoveState) (interface{}, bool) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Empty returns true if map does not contain any elements
|
||||||
|
func (lhmap *LinkedHashmap) Empty() bool {
|
||||||
|
return lhmap.Size() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns number of elements in the map.
|
||||||
|
func (lhmap *LinkedHashmap) Size() uint {
|
||||||
|
return lhmap.list.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns all keys left to right (head to tail)
|
||||||
|
func (lhmap *LinkedHashmap) Keys() []interface{} {
|
||||||
|
return lhmap.list.Values()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values returns all values in-order based on the key.
|
||||||
|
func (lhmap *LinkedHashmap) Values() []interface{} {
|
||||||
|
values := make([]interface{}, lhmap.Size())
|
||||||
|
count := 0
|
||||||
|
lhmap.list.Traversal(func(key interface{}) bool {
|
||||||
|
values[count] = lhmap.hmap[key]
|
||||||
|
count++
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string
|
||||||
|
func (lhmap *LinkedHashmap) String() string {
|
||||||
|
return spew.Sprint(lhmap.Values())
|
||||||
|
}
|
174
map/linked_hashmap/linked_hashmap_test.go
Normal file
174
map/linked_hashmap/linked_hashmap_test.go
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
package linkedhashmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPush(t *testing.T) {
|
||||||
|
lhm := New()
|
||||||
|
lhm.PushFront(1, "1")
|
||||||
|
lhm.PushBack("2", 2)
|
||||||
|
var values []interface{}
|
||||||
|
values = lhm.Values()
|
||||||
|
|
||||||
|
var testType reflect.Type
|
||||||
|
|
||||||
|
if testType = reflect.TypeOf(values[0]); testType.String() != "string" {
|
||||||
|
t.Error(testType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testType = reflect.TypeOf(values[1]); testType.String() != "int" {
|
||||||
|
t.Error(testType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 2
|
||||||
|
lhm.PushFront(4, "4") // 4 1 2
|
||||||
|
lhm.PushBack("3", 3) // 4 1 2 3
|
||||||
|
|
||||||
|
if lhm.String() != "[4 1 2 3]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
lhm.Put(5, 5)
|
||||||
|
if lhm.String() != "[4 1 2 3 5]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBase(t *testing.T) {
|
||||||
|
lhm := New()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
lhm.PushBack(i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.Empty() {
|
||||||
|
t.Error("why lhm Enpty, check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.Size() != 10 {
|
||||||
|
t.Error("why lhm Size != 10, check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
lhm.Clear()
|
||||||
|
if !lhm.Empty() {
|
||||||
|
t.Error("why lhm Clear not Empty, check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.Size() != 0 {
|
||||||
|
t.Error("why lhm Size != 0, check it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
lhm := New()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
lhm.PushBack(i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
lhm.PushBack(i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.Size() != 10 {
|
||||||
|
t.Error("why lhm Size != 10, check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if v, ok := lhm.Get(i); !ok || v != i {
|
||||||
|
t.Error("ok is ", ok, " get value is ", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInsert(t *testing.T) {
|
||||||
|
lhm := New()
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
lhm.Insert(0, i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.String() != "[4 3 2 1 0]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lhm.Insert(2, 5, 5) {
|
||||||
|
t.Error("Insert 2 5 5 error check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.String() != "[4 3 5 2 1 0]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !lhm.Insert(lhm.Size(), 6, 6) {
|
||||||
|
t.Error("Insert Size() error check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.String() != "[4 3 5 2 1 0 6]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemove(t *testing.T) {
|
||||||
|
lhm := New()
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
lhm.PushBack(i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultStr = "[0 1 2 3 4 5 6 7 8 9]"
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if lhm.String() != resultStr {
|
||||||
|
t.Error(lhm.String(), resultStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
lhm.Remove(i)
|
||||||
|
if lhm.Size() != uint(9-i) {
|
||||||
|
t.Error("why lhm Size != ", uint(9-i), ", check it")
|
||||||
|
}
|
||||||
|
|
||||||
|
resultStr = resultStr[0:1] + resultStr[3:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.Size() != 0 {
|
||||||
|
t.Error(lhm.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
lhm.PushFront(i, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
if i >= 5 {
|
||||||
|
lhm.Remove(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if lhm.String() != "[4 3 2 1 0]" {
|
||||||
|
t.Error(lhm.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveIndex [4 3 2 1 0]
|
||||||
|
|
||||||
|
if value, _ := lhm.RemoveIndex(2); value != 2 {
|
||||||
|
t.Error("[4 3 2 1 0] remove index 2, value is 2, but now is", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// [4 3 1 0]
|
||||||
|
if value, _ := lhm.RemoveIndex(2); value != 1 {
|
||||||
|
t.Error("[4 3 1 0] remove index 2, value is 1, but now is", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// [4 3 0]
|
||||||
|
if value, _ := lhm.RemoveIndex(2); value != 0 {
|
||||||
|
t.Error("[4 3 0] remove index 2, value is 0, but now is", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// [4 3]
|
||||||
|
if value, _ := lhm.RemoveIndex(2); value != nil {
|
||||||
|
t.Error("[4 3] remove index 2, value is nil, but now is", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// [4 3]
|
||||||
|
if value, _ := lhm.RemoveIndex(0); value != 4 {
|
||||||
|
t.Error("[4 3] remove index 0, value is 4, but now is", value)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user