完善: linkedlist
This commit is contained in:
parent
0fad6aae53
commit
76ca4e2a0e
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,11 @@
|
|||
package linkedlist
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
prev *Node
|
||||
|
@ -18,12 +23,6 @@ type LinkedList struct {
|
|||
size uint
|
||||
}
|
||||
|
||||
// var nodePool *sync.Pool = &sync.Pool{
|
||||
// New: func() interface{} {
|
||||
// return &Node{}
|
||||
// },
|
||||
// }
|
||||
|
||||
func New() *LinkedList {
|
||||
l := &LinkedList{}
|
||||
l.head = &Node{}
|
||||
|
@ -37,6 +36,14 @@ func New() *LinkedList {
|
|||
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
|
||||
|
@ -191,7 +198,7 @@ func (l *LinkedList) Index(idx uint) (interface{}, bool) {
|
|||
}
|
||||
|
||||
func (l *LinkedList) Insert(idx uint, values ...interface{}) {
|
||||
if idx > l.size {
|
||||
if idx > l.size { // 插入的方式 可能导致size的范围判断不一样
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -265,13 +272,37 @@ func (l *LinkedList) Insert(idx uint, values ...interface{}) {
|
|||
l.size += uint(len(values))
|
||||
}
|
||||
|
||||
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)
|
||||
// 头部
|
||||
for cur := l.head.next; cur != nil; cur = cur.next {
|
||||
isInsert := every(idx, cur.value)
|
||||
if isInsert != 0 { // 1 为前 -1 为后 insert here(-1) ->cur-> insert here(1)
|
||||
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
|
||||
|
||||
|
@ -285,13 +316,13 @@ func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) int, value
|
|||
end = node
|
||||
}
|
||||
|
||||
if isInsert < 0 {
|
||||
if insertState == InsertBack {
|
||||
cprev := cur.prev
|
||||
cprev.next = start
|
||||
start.prev = cprev
|
||||
end.next = cur
|
||||
cur.prev = end
|
||||
} else {
|
||||
} else { // InsertFront
|
||||
cnext := cur.next
|
||||
cnext.prev = end
|
||||
start.prev = cur
|
||||
|
@ -300,8 +331,11 @@ func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) int, value
|
|||
}
|
||||
|
||||
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) {
|
||||
if idx >= l.size {
|
||||
panic(fmt.Sprintf("out of list range, size is %d, idx is %d", l.size, idx))
|
||||
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--
|
||||
|
@ -346,21 +381,50 @@ func (l *LinkedList) Remove(idx uint) (interface{}, bool) {
|
|||
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)
|
||||
TOPFOR:
|
||||
for cur := l.head.next; cur != l.tail; idx++ {
|
||||
j := every(idx, cur.value)
|
||||
switch {
|
||||
case j > 0:
|
||||
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
|
||||
case j < 0:
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -377,6 +441,10 @@ func (l *LinkedList) Values() (result []interface{}) {
|
|||
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) {
|
|
@ -90,7 +90,28 @@ 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())
|
||||
}
|
||||
|
||||
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]"
|
||||
|
@ -149,13 +170,13 @@ func TestInsertIf(t *testing.T) {
|
|||
l.Insert(0, i)
|
||||
}
|
||||
|
||||
// "[4 3 2 1 0]"
|
||||
// "[4 3 2 1 0]" 插入两个11
|
||||
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 {
|
||||
return 1
|
||||
return InsertFront
|
||||
}
|
||||
return 0
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
|
@ -168,11 +189,11 @@ func TestInsertIf(t *testing.T) {
|
|||
|
||||
// "[4 3 2 1 0]"
|
||||
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 {
|
||||
return -1
|
||||
return InsertBack
|
||||
}
|
||||
return 0
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
|
@ -183,11 +204,11 @@ func TestInsertIf(t *testing.T) {
|
|||
|
||||
// "[4 3 2 1 0]"
|
||||
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 {
|
||||
return 1
|
||||
return InsertFront
|
||||
}
|
||||
return 0
|
||||
return UninsertAndContinue
|
||||
}, 11)
|
||||
}
|
||||
|
||||
|
@ -385,13 +406,10 @@ func TestRemove(t *testing.T) {
|
|||
t.Error("should be [3 2 1] but result is", result, "Size is", l.Size())
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err == nil {
|
||||
t.Error("should be out of range but is not")
|
||||
}
|
||||
}()
|
||||
if _, rvalue := l.Remove(3); rvalue != false {
|
||||
t.Error("l is empty")
|
||||
}
|
||||
|
||||
l.Remove(3)
|
||||
}
|
||||
|
||||
func TestRemoveIf(t *testing.T) {
|
||||
|
@ -401,11 +419,11 @@ func TestRemoveIf(t *testing.T) {
|
|||
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 {
|
||||
return 1
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return 0
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
if result[0] != 0 {
|
||||
t.Error("result should is", 0)
|
||||
|
@ -414,11 +432,11 @@ func TestRemoveIf(t *testing.T) {
|
|||
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 {
|
||||
return 1
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return 0
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
if result[0] != 4 {
|
||||
t.Error("result should is", 4)
|
||||
|
@ -433,11 +451,11 @@ func TestRemoveIf(t *testing.T) {
|
|||
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 {
|
||||
return 1
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return 0
|
||||
return UnremoveAndContinue
|
||||
}); ok {
|
||||
t.Error("should not be ok and result is nil")
|
||||
} else {
|
||||
|
@ -451,17 +469,154 @@ func TestRemoveIf(t *testing.T) {
|
|||
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 {
|
||||
return 1
|
||||
return RemoveAndContinue
|
||||
}
|
||||
return 0
|
||||
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) {
|
121
map/linked_hashmap/linked_hashmap.go
Normal file
121
map/linked_hashmap/linked_hashmap.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package linkedhashmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// PushBack 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
|
||||
func (lhmap *LinkedHashmap) Insert(idx uint, key interface{}, value interface{}) bool {
|
||||
if _, ok := lhmap.hmap[key]; !ok {
|
||||
|
||||
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 {
|
||||
panic(fmt.Sprintf("out of list range, size is %d, idx is %d", lhmap.list.Size(), idx))
|
||||
}
|
||||
|
||||
if _, 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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
98
map/linked_hashmap/linked_hashmap_test.go
Normal file
98
map/linked_hashmap/linked_hashmap_test.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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 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:]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user