完善: linkedlist

This commit is contained in:
huangsimin 2019-07-19 17:41:28 +08:00
parent 0fad6aae53
commit 76ca4e2a0e
7 changed files with 580 additions and 51 deletions

View 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
}

View File

@ -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) {

View File

@ -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) {

View 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())
}

View 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:]
}
}